When my users log into the website their first name, last name and ID are missing from the session data because my session data is coded to take post data and submit into the session table in my database.
Because user logs in with email and password in my session data only email appears and nothing else does.
How can I make first name, last name and id appear in my session table in my db? I want to some how grab these details from the database when user is logging in and provide it in my $u_data array so it get's posted upload login success.
Here is my code:
<?php
class Login_Model extends CI_Model {
public function checkLogin() {
$this->db->where('email', $this->input->post('email')); //compare db email to email entered in form
$this->db->where('password', $this->hashed()); //compare db password to hashed user password
$query = $this->db->get('users'); //get the above info from 'user' table
if ($query->num_rows() == 1) { //if number of rows returned is 1
$u_data = array( //new variable with session data
'user_id' => $this->db->insert_id(),
'email' => $this->input->post('email'),
'first_name' => $this->input->post('first_name'),
'last_name' => $this->input->post('last_name'),
'logged_in' => TRUE
);
$this->session->set_userdata($u_data); //send data from variable to db session
return TRUE;
} else {
return FALSE;
}
}
public function hashed() { //hashing method
// sha1 and salt password
$password = $this->encrypt->sha1($this->input->post('password')); //encrypt user password
$salt = $this->config->item('encryption_key'); //grab static salt from config file
$start_hash = sha1($salt . $password);
$end_hash = sha1($password . $salt);
$hashed = sha1($start_hash . $password . $end_hash);
return $hashed;
}
}
If you're tracking sessions in your DB, two solutions come to mind.
First, you could select the first/last from the user table and insert it into the session table. This requires changes to your application.
Second, you could set up a view for your application, in which the session table is automatically joined with the appropriate user, but that assumes you already have some unique identifier for which user it is in the session (was that the email address?*). This solution would not require any changes to the application code, but would require changes to the DB, which may be the preferred method depending upon your deployment requirements (or it may not :) ).
* as a side note, if you're using email addresses for unique identifiers, be aware that some people share email addresses as you decide if this is the right solution for you.
It'd be as simple as doing something like:
session_start();
$_SESSION['userdata'] = $u_data;
within your CheckLogin method. The session is just a regular PHP array that happens to be automatically preserved for you. You can put anything you want into it, but you do have do put things into it yourself - PHP won't do it for you.
comment followup:
gotcha. So, you simply modify you class to fetch that information from the DB once the login's authenticated. I don't know how your DB class works, but instead of merely checking if there's a matching row, fetch the first/last name, using a query something like this:
select firstname, lastname
from users
where email=$email and password=$password
If you get a result row, you know it's a valid login, and then you just retrieve the name data. I have no idea how your db class works, but it shouldn't be too hard to get it to do that.
When I'm working with Auth systems in CodeIgniter I have made it a practice to include the "user" object globally in views, and also globally in my controllers, by fetching the userdata in the constructor, like so...
<?php
class My_Controller extends Controller {
private $the_user; //global var to store current user data
function My_Controller() {
parent::Controller();
$data->the_user = $this->ion_auth->get_user(); //get user data
$this->load->vars($data); //load into all views as $the_user "$the_user"
$this->the_user=$data->the_user; //load into private class variable "$this->the_user"
}
At that point $the_user variable object is available in all views by default AND $this->the_user is always available to controller functions. It always represents the user currently logged in.
I am using Ion_auth for authentication and fetching the user, so that piece you would have to fill in.
I actually just constructed a "How-to" to implement extended Controller classes so all the Auth logic is automatically inherited to all "protected" Controllers.
The following solved this issue for me. I looked at one of my old questions on here and used my common sense.
I made this edit to my code.
if ($query->num_rows() == 1) { //if number of rows returned is 1
$user = $query->result();
$u_data = array( //new variable with session data
'user_id' => $user[0]->id,
'email' => $this->input->post('email'),
'first_name' => $user[0]->first_name,
'last_name' => $user[0]->last_name,
'logged_in' => TRUE
);
Related
I'm currently developing an MLM Website using Codeigniter Framework.
And I am working on registration now. I can register successful with referral user
The problem is every 3 registration using my referral username/id i need to run another query because in 1st and 2nd referral I earned 200. and in 3rd user will refer i will only earn 100.
How can I do that in Codeigniter? anyone done this? please help
Let me throw some light on this
So lets say you make a post for every registration, the post goes to a class names registration and a register method, and the referral id runs as a session (refID). Also, you have a registration model, this is what you should likely do:
class registration extends CI_Controller{
function __construct(){
parent::__construct();
$this->load->model('registration_model');
}
//ensue to check for the existence of the refID session before processing
function register(){
if($_POST){
//first run form validation
//you should have auto loaded the form_validation library
//and created a rules function that carries the form rules
$rules = $this->rules();
$this->form_validation->set_rules($rules);
if($this->form_validation->run() == FALSE){
//load view here
}else{
//first, get post data
//then get the number of registration done by user using the refID
//if registration is greater than 2, set earnings to 100
//set earnings to 200
//then proceed to insert registration and do something else
//get post data, assumed post data
$name = $this->input->post('name');
$email = $this->input->post('email');
//get number of registrations
$numOfRegs = $this->registration_model->getRegByRefID();
//set the earnings from the number of registrations
$earning = $numOfRegs < 3 ? 200 : 100;
//please note that the for $numOfRegs = 4, $earnings will be 100, as this was not specified in the question
//at this point, you have set the earnings, you can proceed to do whatever you wish to do, perhaps insert the records
//please note that this code block just explains what you can likely do after setting the earnings
$insert = array(
"name" => $name,
"email" => $email,
"earning" => $earning
);
$this->registration_model->insert($array);
// then do anything else
}
}else{
//load view here
}
}
}
Now this is how your registration model will look like this
class Registration_model extends CI_Model{
function __construct(){
parent::__construct();
}
function getRegByRefID(){
$refID = $this->session->refID;
return $this->db->get_where('mydb', array("refID" => $refID))->num_rows();
}
}
I hope this explains what you really wants, and helps you. If you find any difficulty, kindly comment and lets sort it out.
I've been searching the internet and have yet to find a solution to the following problem...
We currently have a website developed using Laravel which the user table is a remote Microsoft SQL database. The driver in config/auth.php has been set to "database". All is working fine except for the password reset functionality, which we get the following error:
UnexpectedValueException in PasswordBroker.php line 238: User must implement CanResetPassword interface.
From my limited understanding of Laravel (this is my first experiance with Laravel), the Eloquent driver has support for the CanResetPassword functionality, however, this has not been implemented in the Database User Provider by Laravel, hence the error.
So my question is thus, has anyone had a configuration where they have the driver to “Database” and implemented a reset password functionality? All the examples I have seen to date relate to using the Eloquent model, which from my understanding of Laravel is not an option since during the initial development we had to change the driver from Eloquent to database to get the remote Microsoft SQL server working in the first place. Moving the Microsoft SQL database to a local database is not an option I’m afraid.
Alternatively, if anyone has implemented another method of a user resetting their password using an email address I would be open to suggestions.
To write your own password reset logic, you can still use the default migration that comes out of the box or simply create yours. The most important part is the token. Because you are making your own password reset, you have a couple of decisions to make:
Will the token expire?
Can a user use the same token multiple times?
You will need 2 pages, 4 different routes and 4 different functions in the same controller. The 'I forgot my password' page and the 'Reset password' page. In the first page, display a form where you take the user email. And post to the following controller.
//to be added on top as use statements
use DB;
use Auth;
use Hash;
use Carbon;
use App\User;
public function sendPasswordResetToken(Request $request)
{
$user = User::where ('email', $request->email)-first();
if ( !$user ) return redirect()->back()->withErrors(['error' => '404']);
//create a new token to be sent to the user.
DB::table('password_resets')->insert([
'email' => $request->email,
'token' => str_random(60), //change 60 to any length you want
'created_at' => Carbon::now()
]);
$tokenData = DB::table('password_resets')
->where('email', $request->email)->first();
$token = $tokenData->token;
$email = $request->email; // or $email = $tokenData->email;
/**
* Send email to the email above with a link to your password reset
* something like url('password-reset/' . $token)
* Sending email varies according to your Laravel version. Very easy to implement
*/
}
Second part, when the user clicks on the link
/**
* Assuming the URL looks like this
* http://localhost/password-reset/random-string-here
* You check if the user and the token exist and display a page
*/
public function showPasswordResetForm($token)
{
$tokenData = DB::table('password_resets')
->where('token', $token)->first();
if ( !$tokenData ) return redirect()->to('home'); //redirect them anywhere you want if the token does not exist.
return view('passwords.show');
}
Display a page with a form containing 2 inputs
- New password password or whateveer you want
- New password confirmation password_confirm or whatever you want
The form should post to the same URL mapped to the following controller. Why? because we still need to use the token to find the actual user.
public function resetPassword(Request $request, $token)
{
//some validation
...
$password = $request->password;
$tokenData = DB::table('password_resets')
->where('token', $token)->first();
$user = User::where('email', $tokenData->email)->first();
if ( !$user ) return redirect()->to('home'); //or wherever you want
$user->password = Hash::make($password);
$user->update(); //or $user->save();
//do we log the user directly or let them login and try their password for the first time ? if yes
Auth::login($user);
// If the user shouldn't reuse the token later, delete the token
DB::table('password_resets')->where('email', $user->email')->delete();
//redirect where we want according to whether they are logged in or not.
}
Don't forget to add routes
Route::get('password-reset', 'PasswordController#showForm'); //I did not create this controller. it simply displays a view with a form to take the email
Route::post('password-reset', 'PasswordController#sendPasswordResetToken');
Route::get('reset-password/{token}', 'PasswordController#showPasswordResetForm');
Route::post('reset-password/{token}', 'PasswordController#resetPassword');
Note: There might be typos or syntax errors because I did not test this and wrote it here directly from the top of my head. If you see an error/exception, don't panick, read the error and search google.
Just to add to what #eddythedove said.
Instead of str_random(60) I used the Laravel way of creating a token:
private function generateToken()
{
// This is set in the .env file
$key = config('app.key');
// Illuminate\Support\Str;
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
return hash_hmac('sha256', Str::random(40), $key);
}
If you find an error in str_random, make sure you import the module first:
use Illuminate\Support\Str;
Then call with Str::random (60).
$key = config('app.key');
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$token = hash_hmac('sha256', Str::random(40), $key);
$dbToken = app(Hasher::class)->make($token);
DB::insert('password_resets', [
'email' => 'email#mail.com',
'token' => $dbToken,
]);
This should work in Laravel 8
The default way Laravel handles the Reset Password has a few security issues.
No track record reset password attempts (Delete the token in the table after success attempt is not acceptable)
No expiry date
No token used time
We always better keep track of these security functions.
I have altered the default table like this on my db migration:
public function up()
{
Schema::table('password_resets', function (Blueprint $table) {
$table->bigIncrements('id');
$table->enum('is_used', ['t', 'f'])->default('f');
$table->dateTime('updated_at')->nullable();
});
}
Instead of deleting the record I simply update the table 'is_used' to 't' and updated_at column.
I use following query to filter is_used = 'f' and created on the same day to gather with token.
$data = PasswordReset::where('token', $token)->where('is_used', 'f')
->whereDate('created_at', '>=', Carbon::today()->toDateString())->first();
i try some code after that i get some solution that will work in laravel 8+.
$key = config('app.key');
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$token = hash_hmac('sha256', Str::random(40), $key);
$dbToken =Hash::make($token);
I found some similar question 1 year ago: Codeigniter Tank Auth add folder upon registration... but not with username included.
I tried to add username (of the registered person in that moment) in module, function create_user.This function create new folder with $user_id and _ like: 1_ but without username of the registered person. I tried to include data $username from $data array, but hoplesss...
if($this->db->insert($this->table_name, $data)) {
$user_id = $this->db->insert_id();
$name = $username;
if(!is_dir(FCPATH."./uploads/".$user_id."_".$name)){
mkdir(FCPATH."./uploads/".$user_id."_".$name , 0777);
}
I know that $data array has username on 1. position for DB write purpose. I tried this possiblity: $name = $username; $name = $data[0]; I found that the library, Tank_auth.php has function get_username(). It is for later purpose when the new user will log in...
How can I get username from $data or DB, table users, cell username ?
Try
$name = $data['username'];
in your code to get the name of the user.
From CodeIgniter Active Record manual, $data is an associative array which will have table field names as keys.
From Tank Auth it is clear that users table contains a field with the name username to store the user's name.
Let me know if this helps.
When updating the user's details, the database will update all the information, although when the page refreshes, the previous information is showing and it does not update unless the user has logged out and logged back in. I am new to CodeIgniter. Could someone please help me or tell me what to do, I would really appreciate it. Thanks in advance.
This is my Model:
function updateAccount($submit_userid, $submit_phone, $submit_address, $submit_eaddress) {
$this->db->where("intMemberID", $submit_userid);
$this->db->update("tblMembers", array(
"strPhoneNumber" => $submit_phone,
"strMemberAddress" => $submit_address,
"strEmailAddress" => $submit_eaddress,
));
}
This is my Controller:
class UpdateController extends CI_Controller {
public function updateAccount() {
$this->load->model('userModel');
$data['userdata'] = $this->session->userdata('userobject');
$submit_userid = $this->input->post('userid');
$submit_phone = $this->input->post('phone');
$submit_address = $this->input->post('address');
$submit_eaddress = $this->input->post('eaddress');
$this->userModel->updateAccount($submit_userid, $submit_phone, $submit_address, $submit_eaddress);
$this->load->view('updateView', $data);
}
}
because you show the old data obtained from the last session. read data directly from database and show it in the view
Your user data is being fetched from the session, rather than the database, you have :
$data['userdata'] = $this->session->userdata('userobject');
This data is put into the session on user login, most likely, thus your problem. You need to change source of the data to
$data['userdata'] = $this->userModel->returnAccount($this->user_id);
or whatever method you have for retrieving the data, to fetch it from your database. Do you have any returnAccount methods in your model? I assume you are not the one who wrote it.
Kohana's ORM comes with built in Kohana's Validation.
As much as I understood, it validates fields that will be added to
the database. It won't work for me because I need to validate fields
that come from $_POST (in simple speaking).
Let me give you an example.
In controller:
$data = Arr::extract($this->request->post(), array('username', 'password', 'password_repeatedly', 'email'));
try {
ORM::factory('User')->sign_up($data);
$this->request->redirect('sign-in');
} catch(ORM_Validation_Exception $exception) {
$errors = $exception->errors('error_messages');
echo 'There were errors:<br />';
echo Debug::dump($errors);
exit;
}
Variable $data is array I need to validate. Method sign_up() is
just custom method in my ORM model that will create user. Sorry about
"echo'es" and "exit's" in controller - I'm just debugging...
My ORM model looks like this:
public function rules() {
return array(
'username' => array(
array('not_empty')
),
'hashed_password' => array(
array('not_empty')
),
'email' => array(
array('not_empty')
)
);
}
public function sign_up($post) {
$salt = $this->_hurricane->generate_salt();
$hashed_password =
$this->_hurricane->hash_password($post['password'], $salt);
$this->username = $post['username'];
$this->hashed_password = $hashed_password;
$this->salt = $salt;
$this->email = $post['email'];
$this->save();
}
I want to check that those three elements of variable $data are
NOT empty! As I said, it checks elements before ORM::save() is
called. And if ypu look closer at my code... in my custom method I
have set hashed_password to be something. It will make it hashed.
Problem is that if user haven't submitted any password (I call that
field 'password' in my HTML form, but 'hashed_password' in
database)... if no password is submitted - it will hash empty string
that will lead to hash anyway. So hashed_password is set!
Then validation is turned on by ORM::save() and in conclusion -
password never can be possibly empty! How to deal with this? Extra
validation in controller? How would you deal with it? Maybe a little
bit different logic?
P.S. Any other suggestions to my code will be appreciated. Thanks in advice!
I don't see what is 'wrong' with your current method.
You can add a condition (Model_user::signup()) to check if the requested password is empty before hashing it (ofc, not setting it at all if it is), so it'll remain empty and make validation fail.
One more thing I can notice here is that the signup method itself is ambiguous, it could easily be done using normal create() combined with a filter for password (so that hashed_password and salt are set when it's changed).
Imho it's also a good practice to use conditional rules / filters, depending on the current objects' state.