Let's suppose that we have poor MVC framework without modules support. Our aim is to implement admin panel with some functionality.
Url for all admin panel features will start with /admin (/admin/add_user, /admin/remove_user) etc.
As we don't have modules, so we have to create Admin controller (yes, this controller probably will be extra large).
<?
class AdminController extends Controller {
public function addUser() {
...
}
public function removeUser() {
...
}
}
?>
How can we protect this methods of being accessed by anyone? .htaccessing /admin folder is not a good idea, I think.
Thank you.
Make all functions private and implement a public function __call which checks whether the user is logged in and has appropriate rights and then either throws an error message or redirects to the correct method.
Well I don't know if your MVC model have it but if so you an use a pre-dispatch mechanism.
Or may be check it in the initialization.
Related
I want to have two folders where save codeigniter's controllers:
/application/controllers
/application/buckets
i'm a order paranoic person and i want to separate two types of my controllers.
In bucket folders the structure app was this:
/application/buckets/example/index.php
/application/buckets/example2/index.php
/application/buckets/example3/index.php
¿Maybe extending the router class?
A working example:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
Extended the core Router class to allow for sub-sub-folders in the controllers directory.
*/
class App_Router extends CI_Router {
function __construct()
{
parent::__construct();
}
function _validate_request($segments)
{
if (count($segments) == 0)
{
return $segments;
}
if (file_exists(APPPATH.'buckets/'.$segments[0].'/index.php'))
{
$this->set_directory(APPPATH.'buckets/'.$segments[0]);
$this->set_class(ucfirst($segments[0]));
$this->set_method(isset($segments[1]) ? $segments[1] : 'index');
return $segments;
}
}
}
You can use Hierarchical MVC(HMVC) with Codeigniter to accomplish this.
For reference, see Modular Extensions - HMVC
You may want to look into parent-child controller ...one extending another. To be more clear you can make as many controller you want.
I Agreed with #Brian Gottier : "what does changing their location do?"
You can perform anything if you have core functionalities in your hands.
You can play around with hooks (CodeIgniter's Hooks feature provides a means to tap into and modify the inner workings of the framework without hacking the core files. When CodeIgniter runs it follows a specific execution process, diagramed in the Application Flow page.)
Create "Base"/"Admin"/"Public"/"XYZ" Controllers in
application/core/MY_Controller.php
and keep rest of your controllers in same application/controller folder
MY_Controller is a basic core library extension. Whenever you create a class with the MY_ prefix the CodeIgniter Loader class will load this after loading the core library.
All we have done here is create a base class that all of our Controllers and "controller types" will inherit. Anything we put in here and assign to $this will be available to anything that extends this class.
Base Controllers are a nice simple way to give you global data, logic and shared code which can be specific to a certain part of your site. They can do all sorts of crazy stuff which I will leave for you to think about.
I Hope this help.
What is the best way to separate admin and front-end for a website in codeigniter where as I was to use all libraries, models, helpers etc. in common, but only controllers and Views will be separate.
I want a more proper way, up for performance, simplicity, and sharing models and libraries etc.
I highly suggest reading the methods outlined in this article by CI dev Phil Sturgeon:
http://philsturgeon.co.uk/blog/2009/07/Create-an-Admin-panel-with-CodeIgniter
My advice: Use modules for organizing your project.
https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/wiki/Home
Create a base controller for the front and/or backend. Something like this:
// core/MY_Controller.php
/**
* Base Controller
*
*/
class MY_Controller extends CI_Controller {
// or MX_Controller if you use HMVC, linked above
function __construct()
{
parent::__construct();
// Load shared resources here or in autoload.php
}
}
/**
* Back end Controller
*
*/
class Admin_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
// Check login, load back end dependencies
}
}
/**
* Default Front-end Controller
*
*/
class Public_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
// Load any front-end only dependencies
}
}
Back end controllers will extend Admin_Controller, and front end controllers will extend Public_Controller. The front end base controller is not really necessary, but there as an example, and can be useful. You can extend MY_Controller instead if you want.
Use URI routing where needed, and create separate controllers for your front end and back end. All helpers, classes, models etc. can be shared if both the front and back end controllers live in the same application.
I use a very simple approach: file folders. Check out the CI User Guide section, Organizing Your Controllers into Sub-folders.
I have my public-facing website built as any other would be built with CodeIgniter. Then I have two additional folders, controllers/admin and views/admin.
The admin controllers are accessed via http://[hostname]/admin/controller, and behave just as any other controller except they have specific authentication checks. Likewise, the views are simply called with the folder name included: $this->load->view('admin/theview');.
I haven't found a reason to do anything more complicated than that.
You all can find complete solution over here, https://github.com/bhuban/modular
Module separation for admin and front-end using HMVC and template separation using template libraries
I am using two third party libraries, you can find it in zip file.
HMVC for modular developed by wiredesignz
Template engine for templating by Phil Sturgeon
Just unzip it into your webserver root directory and run
localhost/modular for front-end
and
localhost/modular/admin for back-end
application/back-modules, it is for the back-end modules
application/front-modules, it is for the front-end modules
similarly
templates/admin for the back-end templates
templates/front for the front-end templates
themes/admin for the back-end themes
themes/front for the front-end themes
Nothing hacked in original code just configured using config.php and index.php
I'm currently working on CI for my website, and i'm having some trouble about extending Controller_CI.
I have one controller that deals with login/signin actions, which doesn't need authentication, and others controllers that check if a user session exists before loading content.
For that purpose, I created MY_Controller class and add authentication code in the constructor.
Then I made all my controller extend MY_Controller, except the first one that still extends Controller_CI
My question is : Is it the right way to deals with authentication ? Is it still possible to use Controller_CI even if it's extended ?
I found another pattern :
http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-Base-Classes-Keeping-it-DRY
I guess it's better, but still, I don't understand why not using the first solution.
Thanks
Extending controller class for that purpose will work, but this solution is not much flexible. I would rather create a library that handles authentication, and run it from a controller when it is desired. Please read http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html for details about creating custom libraries in CI.
Please remember you can only extend the CI_Controller with MY_Controller only once. In that aspects it's not a good idea. Suppose you want to implement another feature (e.g. a piece of code that makes a specific entry in the log) for some controllers, but not necessarily the controllers that need authentication you cannot make another MY_Controller.
Using a library is a better thing.
I'm using the flexi auth library on a big CI site. On every controller that requires authentication I just add the following:
public function __construct() {
parent::__construct();
$this->load->library('flexi_auth');
if (!$this->flexi_auth->is_logged_in())
redirect('auth/login');
}
I think a combination of what Phil Sturgeon suggests in that blog post and using a library would be best. So I would create a core controller (by that I mean a controller you place into application/core that extends CI_Controller) called MY_Controller which will look something like this
class MY_Controller extends CI_Controller
{
function __construct()
{
parent::__construct();
}
//Any other functions you want
}
Then judging by your question you currently have controllers that fit into two categories
Controllers that do require a logged in user before they do
anything
Controllers that don't require a logged in user before they do anything
So I would then create another controller in the /application/core directory that extends MY_Controller but in its constructor it checks to see if the user is logged in
class Auth_Controller extends My_Controller
{
function __construct()
{
parent::__construct();
//Check to see if the user is logged in
$this->load->library('authentication');
if(!$this->authentication->user_logged_in())
{
redirect('/login');
}
}
//Any other functions you want
}
Now when you create you controller you can choose which one of the core controllers you want to extend. If its a controller than doesn't require a logged in user you can extend MY_Controller but if it does required a logged in user you can extend Auth_Controller. That way it means you only need to do the user login check once in your code.
Like others have said if may be a good idea to place any authentication code into a library as that's a better place to put it than in a controller.
Summary
So to summarise by having all of your controllers extend core controllers rather than CI_Controller it should cut down on code repetition.
I also currently working on a CI project and had the same issue. I have came up with a different solution to deal with the authentication.
I extended the core controller as bellow,
class MY_Controller extends CI_Controller
{
public $data = array();
public $calledClass ;
public $calledMethod ;
public function __construct()
{
parent::__construct();
$authException['authentication']['login'] = true;
$authException['authentication']['logout'] = true;
$authException['welcome']['index'] = true;
$this->load->library("router");
$this->calledClass = $this->router->fetch_class();
$this->calledMethod = $this->router->fetch_method();
if(!#$authentication[$this->calledClass][$authentication->calledMethod] && !Auth::isUserLoggedIn())
{
# IS_AJAX is a contant defined in the contants.php
# define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
if(IS_AJAX)
{
# if this is an AJAX call, it sets a value in the header ,
# which can be captured in the AJAX response
# to redirect the user to the login page.
$this->output->set_header("auth-him:1");
exit;
}
else
{
redirect("authentication/login");
}
}
}
}
Hope the code above is clear and this helps.
To extend core controller more than one time, If you still need to use 2 controllers to handle authentication, I have followed this method
https://stackoverflow.com/a/22125436/567854
Hope this also helps :)
So, i have some problem.
I just want to create some website where visitor can interact with my site if they're registered.
Let say they've provided their username,email,password, blah..blah..blah...
And then after they provided their blah..blah..blah.. it will autologin (if their data is passed) to my site.
After they logged in my site, they must provided more data again, like they uploaded their profile picture, how they control their privacy in my site, like step by step registration.
I don't want they interact with my site, until they complete their registration.
How do i make every page in my site looks like registration page until they finished their registration.
It's not like i will give this kind of function right.
if(is_login()){
if(is_registration_complete()){
//you're free to go
} else {
// complete your registration first
}
} else {
//you're not logged in
}
In my every controller, if you know what I mean :)
How do I create this function globaly?
If their registration isn't complete, they will go to registration controller, in every routes.
If they complete their registration, they will go to the, yeah you know the default routes.
I'm so sorry if my English is bad, English isn't my native language, sorry for grammar mistakes :)
The easiest is probably to create a library with your checking function and then to include it in the Constructor of the impacted ControllerS :
class Blog extends CI_Controller {
public function __construct()
{
parent::__construct();
// Load the lib here or Autoload
$this->load->library('mylogincheckhelper');
$this->mylogincheckhelper->is_complete();
}
}
And then you do all the ckecks and routing in the Lib.
create a view with your post-registering stuff and make them conditionally visible. and include the view in your templates.
One way you can do it is to create a custom controller by extend the core CI_Controller. Then you can have your page controllers extend from your custom controllers. By extending, you inherit the functions of the parent, as well as run the parent constructor (or run it if you override it), making them "globally available" to whoever extends it.
//extend the core controller
class MY_Controller extends CI_Controller {
//override to provide additional functionality
public function __construct(){
//run the core controller
parent::__construct();
//then do your login and registration checks here
//you can put code here, call another function or load a helper class
//or better, redirect them to your registration page
}
}
//your page's controller extending from your custom controller
class Page extends MY_Controller {
//not overriding the constructor will execute the parent constructor
//every page that extends your extended controller will inherit it's functions
//and execute it's constructor
}
I am developing a site in codeigniter divided into modules using HMVC. I want the modules to be enabled/disabled by an administrator, and following is how I am planning to achieve it. Since I don't have much experience in PHP/Codeigniter, the following way could be very wrong, so am looking for suggestions/feedbacks:
DB Table: Modules
ID | NAME | STATE
Above table will contain all the module information, and the state field will contain the disabled/enabled value(0 or 1).
I am going to extend the main CI_Controller, and have a function to check the status of the module:
class MY_Controller extends CI_Controller{
public function __construct()
{
parent::__construct();
$this->load->Model('Module_model'); //loads the module model
}
function check_module_state($module_name = '')
{
return $this->Module_model->getState($module_name); //the model returns TRUE or FALSE
}
Now, in the constructor of every controller, I will extend the MY_Controller class, and call the check_module_state and if it returns FALSE, will redirect the user to a "Section Disabled Page";
class Module1 extends MY_Controller{
public function __construct()
{
parent::__construct();
if($this->check_module_state('module1') == FALSE)
redirect('module_disabled', 'location');
}
}
Will the above work, is there a better and easier alternative?
Thanks
It looks ok. How you describe the functionality sounds good. I would however say that if a module is disabled it isn't necessary to tell people that it is disabled.
How I would approach this problem is as below.
I would use the module table to construct the navigation items. If a module is enabled allow a link to be displayed to that module. If the module is disabled no link is displayed. This would not mean you can get rid of security in your controllers as people may still URL Surf. In the case of URL Surfing to a disabled module I would silently re-direct to a default module, for example, the site root (Index).