Passing data to the view through the constructor method in Codeigniter - php

I am currently using the codeigniter tank_auth, at the start of every controller method I have to do the following:
$data['profile'] = $this->tank_auth->get_profile();
The main reason I do this is to display the current logged in username, and also get their privilege level.
I am going over the code trying to go by the DRY principle and have moved a lot of repeated code over to the _constructor method (Like checking if the user is logged in). I am just wondering if there is a way to move this code from the start of every method to the constructor.
My current constructor method looks like so:
public function __construct()
{
parent::__construct();
// If the user isn't logged in redirect to login page.
if (!$this->tank_auth->is_logged_in())
redirect('auth/login');
}
Thanks!

Add variable $data to the controller and use it for all your view data. For example:
public function __construct()
{
parent::__construct();
$this->data['profile'] = $this->tank_auth->get_profile();
}
When calling the view remember to call it like this:
$this->load->view('my_view', $this->data);

You can also extend CI_Controller with MY_Controller and put the login check in the constructor of MY_Controller. Just extend all controllers which need this check from MY_Controller instead of CI_Controller.

Related

How is the right way to implement login on CodeIgniter?

I'm practicing Codeigniter framework using a small project from my friends. Each pages need to load layout view and content view separately. The layout show users login info (logged or not, name, picture, etc.). The question is, how to show login info for each action efficiently? Most of the action will load the layout view, so i need to do that right.
I do implement a helper to get user model, but is that right?
You can use the following method:-
In one separate model constructor function check the login details
class Auth extends CI_Model {
public function __construct(){
parent::__construct();
$this->load->model('loginModel');
$this->load->library('session');
if(!$this->loginModel->isLogin()){
$this->session->sess_destroy();
redirect('index.php/auth/login','refresh');
exit;
}
}
}
Then in required controllers include the model in the controller constructor function
class Main extends CI_Controller {
public function __construct(){
parent::__construct();
$this->load->model('auth');
}
}
No need to check all the controller action's if you added in the controller constructor it will check for all the actions
Frist Create Login Controller, in that controller
Ask User to login
Check if password is correct. If yes, set session value (say user_id) & redirect to User Controller.
Second Create User Controller, in that controller's constructor function
Check Session user_id exist or not. If no, redirect to login.
It is best to check at constructor because it will check for all the methods in that controller.
Hope it helps.

checking if a users logged in

What is the most secure way of checking if a user is logged in? I am using php's framework, codeigniter.
$loggedIn = $this->session->userdata('is_logged_in'); // returns 1
if($loggedIn == true): ?>
// do something
<?php endif; ?>
Does it matter if this code is in the controller or in a view?
Well, the view is for the presentation logic and in this case you should keep the code in the controller but if it relates with the view, for example, if you have a navigation and if you show different menu for a logged in user then you can use in your controller
$loggedIn = $this->session->userdata('is_logged_in');
// ....
$data['loggedIn'] = $loggedIn;
$this->load->view('viewname', $data)
and pass the variable to the view from the controller and then in the view you can check
<?php if($loggedIn ): ?>
// Show menu for logged in user
<?php else: ?>
// Show a different menu
<?php endif; ?>
Keep only some loops like foreach to build a menu or populating a dropdown e.t.c and if statements (when needed) in the view.
When you _construct the controller, you could find if they are logged in or not from the get-go. If they aren't, send them to the login screen:
function __construct() {
parent::__construct();
if (!$this->session->userdata('logged_in')) {
redirect('YourLoginController');
}
}
This should definitely be in the controller.
You could also create a base controller to extend your regular CI_Controller, look up the MY_Controller concept in the docs. In there, you could add a method that checks for authentication and redirects if not, and then call it in your controller methods that require authentication:
class MY_Controller extends Controller{
public $data = array();
function _construct() {
parent::_construct();
$data['logged_in'] = $this->session->userdata('logged_in');
}
function authenticated() {
if (!$this->data['logged_in']) {
redirect('YourLoginController');
}
}
}
And then in YOUR controller:
class Some_Controller extends MY_Controller {
function _construct() {
parent::_construct();
}
// If a method requires authentication
function someMethod() {
$this->authenticated(); //This does nothing if logged in
//It redirects to login if not logged in
//Your stuff.
}
//If a method DOESN'T require login, your $this->data to
//pass to the view has already been started from MY_Controller
//so append the display content you need to that array and
//then pass it to the view
function someOtherMethod() {
$this->data['somecontent'] = "I'm content";
$this->load->view('someView',$this->data);
}
}
Using a concept created from the someOtherMethod() you could then utilize the variable $logged_in in your view to change the content based on a user's authentication status.
The code is better placed in a controller so you can show the proper view based on whether the user is logged in or not. Secure? What are are you trying to avoid? With CI that's the most common way to check and see if a user is currently logged in...as long as you set the is_logged_in variable properly.
While the code will work both in view and controller files, it's a better idea to keep the code in controller not only for the sake of MVC philosophy, but it is also more efficient to keep it in controller.
The reason is that your view files are loaded from controllers. This means that if a user is not logged in, your controller&view files will be still interpreted although they don't have to be. If you check the session in controller, once the controller learns that the session is missing, it can stop interpreting the rest of the code and do some other action such as redirecting user to pages that don't require authentication.

Most efficient way to implement a 'logged-in' check with MVC in PHP?

I know questions similar to this have been asked, but I have been searching through the internet and I can't seem to find exactly what I'm looking for.
The most common answer is to put it in the controller. I liked a particular solution from stackoverflow that had a SessionController and NonSessionController, both extending the main controller but with SessionController checking if the user is logged in before the dispatch.
Does this mean that the controller would look something like this?
class SessionController
{
...
function view()
{
//view thread stuff
}
function post()
{
if loggedin then
{
//post thread stuff
}
}
{
In this situation, it looks like NonSessionController is useless, and that model is only used when every action the controller handles is either strictly for users or non-users, unlike this forum example.
So I guess my question is, is the general concept of the controller above the most efficient way of dealing with login checks when using MVC?
I think the idea would be to have one controller which checks the session and login, and one that doesn't.
I would put the login check in the constructor of the session controller so that way every controller which extends it will check the login.
The session controller would look like
class SessionController
{
public function __construct()
{
if ( ! AuthenticationHelper::isLoggedIn() )
{
// User is not logged in
// Do something, maybe a redirect to login page
}
}
}
Then you can just extend that controller like
class HomeController extends SessionController
{
public function __construct()
{
parent::__construct();
}
public function index()
{
print "This page checks login status";
}
}
I would make a component. If you're writing your own MVC framework then this will be interesting to see how you implement this.
But, basically you need a class to check for session state. But, if you tie yourself to extending a class for logged in and a class for logged out I'd feel you have too much duplicate code. I also just personally don't think its very intuitive. I'd probably wind up losing track of whether or not a controller should extend the Session or NotSession.
I'm actually in the process of writing my own MVC framework and have thought about how I would solve this problem a little. I haven't gotten to where I've actually implemented code so it's more a working theory at this point. :)
Have one controller base class. That class has a property that we'll call $components. Let's make this an array and it can hold the name of classes for things you want to do in a lot of controllers, but doesn't really belong in the controller itself.
Since I'm using the Front Controller design pattern before the action requested is invoked I will gather the array of $components and load the appropriate class file for each entry.
As each $component file is being loaded I will dynamically add that component object to the controller properties. So that a component with name Session might refer to a class named SessionComponent and you can access it in your controller by using $this->Session->do_something() or $this->SessionComponent->do_something()
I kind-of-sort-of ripped the idea from CakePHP. I use Cake as my production PHP framework and a lot of my ideas for the custom built framework I'm working on is, obviously, inspired by Cake.
If you are inside your SessionController, then you shouldn't need to check the loggedin variable for every function, you should do that inside the constructor or the router, if you feel confident enough to manipulate. That way if the user is not logged in, the SessionController file and class would not be loaded at all.
Sorry, no english:
base controller
class Controller{
function handleLogin()
{
if(!Authentication::isLoggedIn())
{
//do stuff - redirect to login page?
}
}
}
someController
class someController extends Controller{
function someAction()
{
//check login
$this->handleLogin();
//do someAction stuff
}
}

All admin/user functions checking if he/she is logged in - How to avoid this?

I am very, very new with MVC (just started yesterday) so this question is probably stupid, but I need to know how to check automatically if user is logged in on my functions that are in admin/user models.
I can put the checking in construct, this would help, but I have several models and maybe there is some even better way. I hope you will understand better what I want after you see my folder structure and code. Oh, and by the way - I use Code Igniter 2.0
Folders:
controllers/
../admin/
../../item.php
../../cat.php
Let's see my item.php file...
<?php
class Item extends CI_Controller
{
function Index()
{
//Checking if admin is logged in on every function is bad
/*
* Is it possible to somehow make all admin functions go through
* some kind of Admin class that will check automatically?
*/
$isLogged = $this->session->userdata('is_logged_in');
if ($isLogged == true)
{
$this->load->view('admin/item/main');
}
else
{
$this->load->view('admin/login');
}
}
function Add()
{
$this->load->view('admin/item/add');
}
function Edit()
{
$this->load->view('admin/item/edit');
}
function Delete()
{
$this->load->view('admin/item/delete');
}
}
I hope that this is easy question, thanks in advance :)
I would implement the login-function in CI_Controller.
Then I would set an protected variable in Item protected $loginRequired = true;.
In function __construct() or Item() I would call parent::isLoginRequired($this->loginRequired) which checks if a login is required.
I would also redirect to a specific login page with a parameter which redirects the user back to the page he needs to be logged in.
Make a new class, for example, My_Controller extends Ci_Controller and write some auth checker code in it... in controller file just extend My_Controller
what i usually do is -like Teeed recommends- Create my own controller Class which is between the CI_Controller and each controller you might create.
In that class (MY_Controller) you can instantiate a model which handles all user related data and logics (loading session data, executing specific checks, etc..) and finally set as class variables those results, so you will end up having:
$this->isLogged ;
$this->isPaying ;
$this->isPlatinumMember ;
etc..
in any of your classes extending from MY_Controller
that makes very easy to check any condition within any of your Controllers.

How to make user object available across pages in CodeIgniter?

I'm fairly new to CodeIgniter and I'm using Ion Auth for user authorization. With the Ion Auth library, you get a user object like:
$user = $this->ion_auth->get_user();
echo $user->email;
If a user is logged in, I want the $user object to be available on any of the pages (in any of the controllers). How can I do this? (I'm using CodeIgniter 2)
This blog post of mine goes into a lot of detail in specifically using Ion_Auth to allow your entire application (including views) to access your current user's information.
The short version... (specifically for the topic at hand)
Adding this to your MY_Controller.php file
class User_Controller extends CI_Controller {
protected $the_user;
public function __construct() {
parent::__construct();
if($this->ion_auth->logged_in()) {
$data->the_user = $this->ion_auth->get_user();
$this->the_user = $data->the_user;
$this->load->vars($data);
}
else {
redirect('/');
}
}
}
Then in your application just create your controller like this
class App_Controller extends User_Controller {
public function __construct() {
parent::__construct();
}
function index() {
//do stuff
}
}
Then not only in your controller will you have access to $this->the_user but you will also have $the_user loaded into every view with $this->load->vars()
Normally you'd cache something like this in the session, however I've moved away from that in most of my CI apps.
An example: you log the user in (caching the user data) and then they go to update their email on their profile page. You now have to reload you cache. Many other things could drive this reload. Usually the most I cache any more is the ID, then I do what you're doing and get the user's data on any page I need it.
One thing I found that helps is to have base controllers. For example I have a RegisteredUserController. Any controller whose actions all require the user to be logged in extend this. That way I can keep the logged in check and things like get the user data in one spot (in the constructor). For example:
class RegisteredUserController extends CI_Controller {
var $user;
function __construct() {
parent::__construct();
$this->user = $this->ion_auth->get_user();
}
}
Then any controller that extends RegisteredUserController instead of just controller can get to the user with $this->user. Following this pattern would get it on every page (that extends the controller) without resorting to caching.

Categories