I'm using HMVC in CodeIgniter https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/wiki/Home
How do I setup a controller that would automatically run when accessing a user-only page.
This is for the purpose of checking if a user is currently logged in or not. I've already made a helper to check if user is logged in:
<?php
if(!defined('BASEPATH')) exit('No direct script access allowed');
if (!function_exists('is_logged_in')){
function is_logged_in(){
$CI =& get_instance();
$logged_in = FALSE;
$user_data = $CI->session->userdata('logged_in');
if(!empty($user_data)){
$logged_in = TRUE;
}
return $logged_in;
}
}
But the only thing that I know is to call this method on the constructor of each controller on each of the modules. I would be repeating the same code on every controller just to check if the user is logged in. Basically I want this function to be called everytime a user tries to access something inside the modules directory.
You can use _remap() for this. You can put this in MY_Controller if you are using one, for more information read the Controller User Guide
Here is something you can start with.
function _remap($method)
{
if (method_exists($this, $method) && $this-my_custom_helper->is_logged_in())
{
$this->$method();
}
else
{
redirect('/auth/login/');
}
}
One option is to extend the main controller class(CI_contorller I guess) and call this helper method in the that controller's constructor. Then extend all the other user related controller from this new controller.
Related
in codeigniter I have my main controller:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Main extends CI_Controller
{
public function index()
{
$this->load->library('../controllers/forum');
$obj = new $this->forum();
$obj->test();
}
}
And the controller I'm trying to access:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Forum extends CI_Controller
{
function __construct()
{
echo "testing1";
$this->load->library('session');
parent::__construct();
$this->load->database();
$this->load->model('model_forum');
}
public function index(){
}
public function test(){
echo "testing2";
$this->data['forums'] = $this->model_forum->getForums();
$this->load->view('homepage', $this->data);
}
}
Everything is fine with my model_forum.php file, because it works if I put all the code in Main controller. But if I'm trying to access Forum controller, nothing works, only "testing1" echo goes through. Picture of error:
Anyone has any idea what I'm doing wrong? I'm new to PHP and codeigniter so I'm struggling a little bit. Thanks in advance.
You can't load a controller from a controller in CI - unless you use HMVC or something.
You should think about your architecture a bit. If you need to call a controller method from another controller, then you should probably abstract that code out to a helper or library and call it from both controllers.
UPDATE
After reading your question again, I realize that your end goal is not necessarily HMVC, but URI manipulation. Correct me if I'm wrong, but it seems like you're trying to accomplish URLs with the first section being the method name and leave out the controller name altogether.
If this is the case, you'd get a cleaner solution by getting creative with your routes.
For a really basic example, say you have two controllers, controller1 and controller2. Controller1 has a method method_1 - and controller2 has a method method_2.
You can set up routes like this:
$route['method_1'] = "controller1/method_1";
$route['method_2'] = "controller2/method_2";
Then, you can call method 1 with a URL like http://example.com/method_1 and method 2 with http://example.com/method_2.
Albeit, this is a hard-coded, very basic, example - but it could get you to where you need to be if all you need to do is remove the controller from the URL.
You could also go with remapping your controllers.
From the docs: "If your controller contains a function named _remap(), it will always get called regardless of what your URI contains.":
public function _remap($method)
{
if ($method == 'some_method')
{
$this->$method();
}
else
{
$this->default_method();
}
}
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.
I'm trying to make a simple routing rule to allow only authenticated users to certain controllers.
To achieve this, I would like to run precontroller hook and check if the user is logged in using ci session. However, I have to know which controller the user wants to access. How do I know this in a hook function?
$this->router->fetch_class();
Extend CI_Controller and this should work.
I dont think that hooks are best practice for what you want to achieve here
you may try the following:
You need to create middle controller that you will extend instead of CI_Controller that will have authentication check and redirect the user to right controller
read this tutorial created by jondavidjohn step by step
http://jondavidjohn.com/blog/2011/01/scalable-login-system-for-codeigniter-ion_auth
You shoud be able to get the idea after 10 mins
Cant you just put the authentication on the controller constructor ?
It will be called when item instantiate and you can do the check there.
Also you can always extend the CI_Controller and put the logic in there so that you can do your check in there (and use this->router->fetch_class() as suggested).
If you don't want to go the extended controller route, and I can see your logic there, then you have to use native PHP here because the CI object doesn't exist in the pre_controller_hook.
So, get the URI, then parse it to find the controller:
$uri = $_SERVER['REQUEST_URI'];
$segments = explode("/", $uri);
// if you're removing index.php from your urls, then
$controller = $segments[0];
// if you're not removing index.php
$controller = $segments[1];
Extend CI_Controller in your autoload library Class.
Something like this:
class MyAuthLibrary extends CI_Controller {
var $ci;
function __construct() {
$this->ci = &get_instance();
$route = $this->ci->router->fetch_class();
if( ($route !== 'login') && !$this->ci->session->userdata('email_address') ) {
redirect('login');
}
}
}
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.
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.