So the problem is, when /MVCTest/manage/dashboard is called, the authenticator is failing because authenticate (a method in the authenticator class) is not finding $_SESSION['user_id'], so it kicks the user back to the login page.
However, if I change the action below to:
action="/MVCTest/manage/login?target=MVCTest/manage/dashboard"
and add the same login function form the index controller to the manageController, everything works fine, but this means I would have to have a login function in every controller that has a page I want to login from (which is every page since I want a user dashboard).
So how do I get the $_SESSION to presist between controllers so I can have a single controller responsible for logging a user in/out?
First, some code...
action="/MVCTest/index/login?target=MVCTest/manage/dashboard" calls the login action of the indexController.
<?php
Class indexController Extends Core_Controller {
public function login(){
$this->registry->authenticator->login($_POST);
}
}
?>
The authenticator object was created in the bootstrap and assigned to the registry. Now for the authenticator object.
<?php
Class Authenticator Extends Base_Model {
public function login($credentials){
//Select user from the database based on email/username
try{
$STH = $this->db->prepare("SELECT * FROM user_account WHERE email = ? OR username = ?");
$STH->bindParam(1, $credentials['login']);
$STH->bindParam(2, $credentials['login']);
$STH->execute();
while($user = $STH->fetch(PDO::FETCH_OBJ)){
$password = $user->user_salt.$credentials['password'];
$password = $this->hashData($password);
try{
if($password === $user->password){
//Active and Verified user exists, set sessions
$random = $this->generateRandomString();
//Build the token
$token = $_SERVER["HTTP_USER_AGENT"] . $random;
$token = $this->hashData($token);
//Setup session variables
session_start();
$_SESSION["token"] = $token;
$_SESSION["user_id"] = $user->id;
//Delete old session records for the user
$STH = $this->db->prepare("DELETE FROM user_session WHERE user_account_id = ?");
$STH->bindParam(1, $user->id);
$STH->execute();
//Insert new session records for the user
try{
$STH = $this->db->prepare("INSERT INTO user_session (user_account_id, session_id, token)
VALUES (?,'".session_id()."', ?);");
$STH->bindParam(1, $user->id);
$STH->bindParam(2, $token);
$STH->execute();
header("Location: /{$_GET['target']}");
exit;
} catch (PDOException $e){
file_put_contents(__SITE_PATH."/logs/errors/MySQLErrors", $e->getMessage()."\n", FILE_APPEND);
die($e->getMessage());
}
} else {
throw new Exception("Password is incorrect!");
}
} catch (Exception $e){
file_put_contents(__SITE_PATH."/logs/errors/LoginErrors", $e->getMessage()."\n", FILE_APPEND);
die($e->getMessage());
}
}
//Email/Username not found
throw new Exception("Email/Username not found!");
} catch (Exception $e) {
file_put_contents(__SITE_PATH."/logs/errors/LoginErrors", $e->getMessage()."\n", FILE_APPEND);
die($e->getMessage());
} catch (PDOException $e){
file_put_contents(__SITE_PATH."/logs/errors/MySQLErrors", $e->getMessage()."\n", FILE_APPEND);
die($e->getMessage());
}
}
}
?>
And finally, my manageController
<?php
session_name();
session_set_cookie_params(3600, "/MVCTest/manage/");
session_start();
Class manageController Extends Core_Controller {
public function index() {
if(isset($_SESSION['user_id'])){
header("Location: /MVCTest/manage/dashboard");
exit;
}
$this->registry->template->show('manage/index');
}
public function dashboard(){
$this->registry->authenticator->authenticate("/MVCTest/manage/");
$this->registry->template->show('manage/dashboard');
}
}
?>
I found the answer. Leave session_name();
session_set_cookie_params(3600, __SITE_PATH.'/MVCTest/manage/'); in the manageController while moving session_start(); to the beginning of the extended Core_Controller while adding a public login function.
The result is that every page can log somebody in; however, I feel like this is bad practice. The problem I see is that every single page call will start a session regardless of if the user is logged in or not. I get the feeling that this is bad, any suggestions?
Look at this code:
//Setup session variables
session_start();
$_SESSION["token"] = $token;
$_SESSION["user_id"] = $user->id;
You must use
session_start();
At the beginning of the file.
Read more about session_start
Related
if(isset($_POST["submit"]))
{
$email = trim($_POST['email']);
$upass = trim($_POST['password']);
if($user_login->login($email,$upass))
{
$user_login->redirect("index.php");
}
}
public function login($email,$upass)
{
try
{
$stmt = $this->conn->prepare("SELECT * FROM table WHERE userEmail=:email_id");
$stmt->execute(array(":email_id"=>$email));
$userRow=$stmt->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() == 1)
{
if($userRow['userStatus']=="Y")
{
if($userRow['userPass']==md5($upass))
{
$_SESSION['userSession'] = $userRow['userID'];
return true;
}
else
{
header("Location: login.php?error");
exit;
}
}
else
{
header("Location: login.php?inactive");
exit;
}
}
else
{
header("Location: login.php?error");
exit;
}
}
catch(PDOException $ex)
{
echo $ex->getMessage();
}
I've granted all the privileges to the database.
The user is able to signup but when loggedin it doesn't log in but also doesn't show any error and directs the user to index.php without creating session.
If you haven't already, I would recommend adding the following line of code to the top of all relevant pages which require Session based integration. Following this, you'll be able to set the session variables.
session_start();
With regards to the previous comment regarding the password Hashing methods, MD5 is considered very insecure compared to other methods of password hashing, including PHP's password_hash() and password_verify() functions.
<?php
$hashed_pass = password_hash($password, PASSWORD_BCRYPT);
if(password_verify($input_pass,$hashed_pass)) {
//Password Matches DB
}
else {
//Pass Doesn't Match DB
}
?>
I also see you use a lot of GET variables for the error messages, such as error and inactive. I would personally reccomend using the POST method on the Login form itself, and return back to itself, and handle the error messages that way, with the backend processes such as logging in etc being handled from the backend class.
The below code may / may not have many hidden errors.
What I want:- I have session which results as if a user is at index.php and is logged, it will redirect to its account folder.
What I got:- In index.php I got see image.
How account folder is prescribed:-
Suppose there are two users, having uname as trial & demo
So the account folder for trial will be http://localhost/Ebooks/new/trial & for demo it will be http://localhost/Ebooks/new/demo
Means account folders are based on their uname
uname is nothing but username
For getting the result I tried:-
index.php
<?php
session_start();
require_once 'class.user.php';
$user_login = new USER();
if($user_login->is_logged_in()!="")
{
$user_login->redirect($uname);
}
if(isset($_POST['btn-login']))
{
$uname = trim($_POST['txtuname']);
$upass = trim($_POST['txtupass']);
if($user_login->login($uname,$upass))
{
$user_login->redirect($uname);
}
}
?>
class.user.php
public function is_logged_in()
{
if(isset($_SESSION['userSession']))
{
return true;
}
}
public function redirect($uname)
{
try{
$stmt = $this->conn->prepare("SELECT * FROM tbl_users WHERE userName=:username");
$stmt->execute(array(":username"=>$uname));
header("Location: $uname");
} catch (Exception $e) {
die('Error! '.$e->getMessage());
}
}
public function logout()
{
session_destroy();
$_SESSION['userSession'] = false;
}
But I get the result as see image.
I request to sort out my problem!
If my error is solved please do not consider the problem is solved. I want basically How to go to account folder using session in PHP, but this may have many hidden problems.
You need a catch if you are goiung to try something:
public function redirect($uname)
{
try{
$stmt = $this->conn->prepare("SELECT * FROM tbl_users WHERE userName=:username");
$stmt->execute(array(":username"=>$uname));
header("Location: $uname");
} catch (Exception $e) {
die('Error! '.$e->getMessage());
}
}
Handle any errors however you will in the catch area.
You need catch block as well with try. I assume you use PDO, so working solution would be following.
public function redirect($uname) {
try{
$stmt = $this->conn->prepare("SELECT * FROM tbl_users WHERE userName=:username");
$stmt->execute(array(":username"=>$uname));
}
catch(PDOException $error) {
return $error->getMessage();
}
header("Location: $uname");
}
I'm building a class to login users, so everything works great on localhost, but when i upload the files to the server, the code doesn't work as espected...
I checked this question Value return when no rows in PDO but i couldn't make it work...
My goal is to be able to retrieve the data from the Database and then check either the password is correct or not. I need 3 feedbacks:
User Doesn't exist
Pass/User combination doesn't match.
All good, proceed and login the user.
First I call the class:
$a = $login->login_user_admin($_POST['user']);
Then I get the result: Updated full class & connection
class Database extends PDO
{
private $dbname = "xxx";
private $host = "localhost";
private $user = "xxx";
private $pass = "xxx";
private $port = 5432;
private $dbh;
public function __construct()
{
try {
$this->dbh = parent::__construct("pgsql:host=$this->host;port=$this->port;dbname=$this->dbname;user=$this->user;password=$this->pass");
} catch(PDOException $e) {
echo $e->getMessage();
}
}
public function close_con()
{
$this->dbh = null;
}
}
class Users
{
private $con;
public function __construct()
{
$this->con = new Database();
$this->con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$this->con->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
public function login_user_admin($user)
{
try{
$stmt = $this->con->prepare("SELECT name,salt,pass FROM users.users_admin WHERE name=? LIMIT 1");
$stmt->execute(array($user));
$this->con->close_con();
return $stmt->fetch(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo $e->getMessage();
}
}
}
Finally I process:
$data = [];
if ($a!=true) {
$data['success'] = false;
$data['message'] = 'User doesn't exist';
}else{
//All good proceed to chk the password.
}
I tried with empty and isset... didn't work on server either, they all work on local tough. I also try using fetchAll() and checking the empty string but i couldn't make it.
I went to check on the PHP versions on the server and local and they both running on 5.5 so I run out of ideas for now and I will appreciate some help on this.
Update!
I upload a file with only this code to check if I am getting any result from the database and I realize I am not,
include '../functions/functions.php';
$login = new Users();
$a = $login->login_user_admin("emirocast");
print_r($a);
var_dump($a);
The only user in the database right now is "emirocast" so i should get the result but i get a bool(false) instead.
The other thing I noticed is that the server is running Postgresql 8.4 and I am running 9.1 locally. Can this be the problem here?
I am storing an USER object inside a session by serialize first, than I am trying to use it on the same page to test it however it doesn't retrieve the data that was initialize everything is blank.
$user = new User();
echo '<br/>' . $user->getUsername(); // Gives me corerct data
userSession(serialize($user)); // Stored into session
$userObj = unserialize($_SESSION['userObj']); // Still get an object of type User
echo $userObj->getUsername(); // This returns blank unlike the first call
If anyone can assist me it will be greatly appreciated, thanks!
userSession Code
function userSession($userObj){
session_start();
$_SESSION['userObj'] = $userObj;
}
USER CLASS
class User{
protected $pdo;
private $id, $username, $banned, $email, $first_name, $last_name, $mobile_phone, $city, $address, $postal_code, $user_type, $active;
// Create a user
public function __construct(){
$con = new Connection();
try{
$this->pdo = $con->getConnection();
}catch (PDOException $e){
echo $e->getMessage(); // Store to file
}
}
Instead of serializing the full User class, try serializing just the data and using the same data to create a new object after.
Basically, what you'd do is add a User->getData() and User->setData() where one would return all the data that is relevant in a format you can save (JSON, serializable Array) and the other would allow you to create a new User object and load this data back in.
I am able to login with user credentials with
try {
$user = ParseUser::logIn("myname", "mypass");
// Do stuff after successful login.
} catch (ParseException $error) {
// The login failed. Check error to see why.
}
but if I try to get the currentUser afterwards with
$currentUser = ParseUser::getCurrentUser();
if ($currentUser) {
// do stuff with the user
} else {
// show the signup or login page
}
$currentUser is not set.
I suspect this more to be a php "issue" that I don't know. I am greatful for any hint for keeping currentUser retained in my code as long I do not log out.
In order for the getCurrentUser() method to work, you must define the type of session storage to use. You can use the ParseSessionStorage class to achieve this:
use Parse\ParseClient;
use Parse\ParseUser;
use Parse\ParseSessionStorage;
session_start();
// Init parse: app_id, rest_key, master_key
ParseClient::initialize('xxx', 'yyy', 'zzz');
// set session storage
ParseClient::setStorage( new ParseSessionStorage() );
try {
$user = ParseUser::logIn("myname", "mypass");
// Do stuff after successful login.
} catch (ParseException $error) {
// The login failed. Check error to see why.
}
$currentUser = ParseUser::getCurrentUser();
print_r( $currentUser );