I have the below code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Login extends MY_Controller
{
function __construct()
{
parent::__construct();
$this->load->model('users/user_model');
$this->load->library('form_validation');
}
function _load_login_page()
{
$this->load->model('sysconfig/sysconfig_model');
$a = $this->sysconfig_model->get_sysconfig();
$row = $a[0];
$this->lang->load('klas',$row->sysconfig_language);
$data['sys_name'] = $row->sysconfig_system_name;
$data['template_name'] = $row->systemplate_name;
$data['css_script'] = base_url().'assets/'.$row->systemplate_name;
if($row->sysconfig_maintenance === 'Y')
{
$this->load->view('sysconfig/maintenance',$data);
}
else {
$this->load->view('login',$data);
}
}
function index()
{
$this->form_validation->set_rules('username', 'Username', 'trim|required|max_length[12]|xss_clean|callback_check_auth');
$this->form_validation->set_rules('password','Password','trim|required');
if($this->form_validation->run($this) == FALSE)
{
$this->_load_login_page();
} else {
redirect('welcome','refresh');
}
}
function check_auth()
{
if($this->user_model->authentication())
{
return TRUE;
}
$this->form_validation->set_message('check_auth',$this->lang->line('invalid_username'));
return FALSE;
}
?>
user_model.php
<?php
class User_Model extends CI_Model
{
function authentication()
{
$this->db->where('useracc_id', $this->input->post('username'));
$this->db->where('useracc_password', md5($this->input->post('password')));
$q = $this->db->get('base_useracc');
if($q->num_rows() == 1)
{
$session_data = array('isUserLogged'=>TRUE);
$this->session->set_userdata($session_data);
return TRUE;
}
}
?>
From here we can see if the user didn't fill the username and password fields, it will show the error and everything works as expected. The problem is, if the user provides an invalid username or password, the error message won't show.
for the information, I already put $lang['invalid_username'] = 'Invalid username or password'; on the language file.
I am doing this using the HMVC technique. Please help me.
You don't seem to be passing any data to your callback function. Callback functions expect the value of the input field to be passed as a parameter. I don't think you can make this work as a form validation callback be because the authentication method presumably needs to know both the password and the username. At present you're not passing any data into your check_auth method or indeed onwards to your user_model->authentication() method. That is why form_validation is ignoring it.
Rather than calling check_auth as a callback, why not run the form_validation first (this is really what it's for - checking the data is correct and sanitised) and then pass the values from your form to your check_auth function as part of an if statement. You will not be able to use the form_validation set_message method to display errors but I think this is a cleaner approach.
To summarise, use the form_validation to check the data you are receiving is ok and display relevant messages if it is not. Authenticating a user based on that information is a separate procedure that I don't think belongs with validation. Do you see the difference?
from the HMVC wiki page :
When using form validation with MX you will need to extend the CI_Form_validation class as shown below, before assigning the current controller as the $CI variable to the form_validation library. This will allow your callback methods to function properly. (This has been discussed on the CI forums also). ie:
<?php
/** application/libraries/MY_Form_validation **/
class MY_Form_validation extends CI_Form_validation
{
public $CI;
}
<?php
class Xyz extends MX_Controller
{
function __construct()
{
parent::__construct();
$this->load->library('form_validation');
$this->form_validation->CI =& $this;
}
}
Related
I was trying to extend codeigniter(3.1.11) form_validation library to add validation rules of my own.
Below is the code written in application/libraries/MY_Form_validation.php.
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
protected $CI;
public function __construct($rules = array())
{
parent::__construct($rules);
// Assign the CodeIgniter super-object
$this->CI =& get_instance();
}
public function snExists($sn){
if (empty($sn)) {
$this->CI->form_validation->set_message('snExists', '{field} is required');
return FALSE;
}else{
$query = $this->CI->db->query("SELECT `sn` FROM `employee` WHERE `sn` = '$sn';");
$numrows = $query->num_rows();
if ($numrows > 0) {
return TRUE;
}else{
$this->CI->form_validation->set_message('snExists', '{field} does not exist');
return FALSE;
}
}
}
}
The issue i am facing is that, when i submit the field empty the validation does not return FALSE.
somehow the if(empty($sn)) is not satisfied and the else is executed.
hope someone could help. Thank you.
So it looks like codeigniter does not call any validation methods if a field is submitted empty. It will just returns TRUE by default. So in my case checking whether $sn is empty is pointless.
Im working on Codeigniter 3.1.9 and completed my form on local machine. i just uploaded my app some moment ago on server and getting error
Unable to access an error message corresponding to your field name
URL.(valid_url_format)
i google alot but unable to fix problem.
Filename: My_Form_validation.php
Location: application\libraries
class MY_Form_validation extends CI_Form_validation{
public function __construct()
{
parent::__construct();
}
function valid_url_format($str){
$pattern = "/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i";
if (!preg_match($pattern, $str)){
$this->set_message('valid_url_format', 'The URL you entered is not correctly formatted.');
return FALSE;
}
return TRUE;
}
function url_exists($url){
$url_data = parse_url($url); // scheme, host, port, path, query
if(!fsockopen($url_data['host'], isset($url_data['port']) ? $url_data['port'] : 80)){
$this->set_message('url_exists', 'The URL you entered is not accessible.');
return FALSE;
}
return TRUE;
}
}
Filename: UrlChecker.php
Location:application\controllers
class UrlChecker extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function _initializing(){
}
public function index()
{
$this->form_validation->set_rules('link', 'URL', 'required|trim|valid_url_format|url_exists');
if ($this->form_validation->run() == FALSE)
{
echo validation_errors('<div class="alert alert-danger" role="alert">', '</div>');
}
else
{
echo 'ok';
}
}
Please check and let me know whats wrong is there hosting version problem or there is something else.
I always use custom validation on the fly and its the first time to try to make a custom library for additional validations, anyways i created and tested it to make sure it works, you got to make sure you follow the naming convention, the file name should be like this: MY_Form_validation.php and save it in your application/libraries then create your class:
class MY_Form_validation extends CI_Form_validation
{
// your rules
}
then you have to create error messages for every method, create a lang file in your application/language/english/form_validation_lang.php and add your custom error messages like this:
$lang['valid_url_format'] = 'The {field} field may only contain valid url.';
$lang['url_exists'] = 'The {field} field already exists';
I have no idea why my CI return wrong value from phpMyAdmin
Model :
<?php
class Post extends CI_Model
{
function __construct()
{
parent::__construct();
}
function getallpost()
{
return $this->db->get('post');
}
}
?>
And
Controller :
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Postc extends CI_Controller {
function index()
{
$this->load->model('post');
$posts=$this->post->getallpost();
echo '<pre>';
print_r($posts);
}
}
?>
enter image description here
You code is not giving you any error, it is doing exactly what you are asking it to do. Perhaps you need to be specific about the information you want to get. You see in your model
function getallpost()
{
return $this->db->get('post');
}
The above function will return you an object. If you want to get an array you need to write
return $this->db->get('post')->result_array();
And make sure you have some data in your post table to print For learning more about query database you should read Codeigniter's Query Builder Class
Change your Model Code
<?php
class Post extends CI_Model
{
function __construct()
{
parent::__construct();
}
function getallpost()
{
$query = $this->db->get('post');
if($query->num_rows() > 0)
{
return $query->result();
}else{
return false;
}
}
}
If you want to get return your result as as array then use
return $this->db->get('post')->result_array();
And if you want to get return your result as object then use
return $this->db->get('post')->result();
I'm not CI programmer, just trying to learn it. Maybe this is wrong approach, please advice.
my controller(not in sub directory) :
class Users extends CI_Controller {
function __construct() {
parent::__construct();
}
public function index($msg = NULL) {
$this->load->helper(array('form'));
$data['msg'] = $msg;
$this->load->view('user/login' , $data);
}
public function process_logout() {
$this->session->sess_destroy();
redirect(base_url());
}
}
And a route for login :
$route['user/login'] = 'users/index';
Problem is when I wanna logout, it shows me 404 because I do not have it in my route :
$route['user/process_logout'] = 'users/process_logout';
and in my view I put logout
When I add that, it works, and that is stuppid to add a route for everything. What I'm I doing wrong, please advice.
Thank you
Don't know why you are trying to implement login feature in index() function. However since you said you are learning CI I'm telling something about _remap() function.
Before that. You can try the following routing:
$route['user/:any'] = 'users/$1';
$route['user/login'] = 'users/index';
If you want to take value immediately after controller segment you need to use _remap() function and this function may be solve your routing problem, i mean you don't need to set routing. Lets implement your code controller 'users' using _remap() function.
class Users extends CI_Controller {
private $sections = array('login', 'logout');
function __construct() {
parent::__construct();
}
public function _remap($method)
{
$section = $this->uri->segment(2);
if(in_array($section, $this->sections))
call_user_func_array(array($this, '_'.$section), array());
else show_404(); // Showing 404 error
}
private function _login()
{
$msg = $this->uri->segment(3);
$this->load->helper(array('form'));
$data['msg'] = $msg;
$this->load->view('user/login' , $data);
}
public function _logout() {
$this->session->sess_destroy();
redirect(base_url());
}
}
I have a controller, which maps to section of my site and all of the pages within it (methods) should only appear if the user is logged in. Otherwise they should be redirected back to a login screen.
To get it working I've just done this:
function index() {
if ($this->session->userdata('logged_in')) {
$this->load->view('main');
} else {
redirect('/login');
}
}
function archive() {
if ($this->session->userdata('logged_in')) {
and so on... repeating that check in each method. What's the simplest way of doing this check once for multiple-or-all methods in the controller?
You can run code in every method of a Controller by running it in the __construct() method:
function __construct()
{
parent::__construct();
if ( ! $this->session->userdata('logged_in'))
{
// Allow some methods?
$allowed = array(
'some_method_in_this_controller',
'other_method_in_this_controller',
);
if ( ! in_array($this->router->fetch_method(), $allowed)
{
redirect('login');
}
}
}
You can remove the "allowed" bits if you want to restrict access to the whole thing, but there are better ways to do this, like creating a base controller:
// Create file application/core/MY_Controller.php
class Auth_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
if ( ! $this->session->userdata('logged_in'))
{
redirect('login');
}
}
}
Then have your restricted controllers extend Auth_Controller instead of CI_Controller. Now your code will be run every time the controller is loaded.
More info on extending core classes: http://www.codeigniter.com/user_guide/general/core_classes.html#extending-core-class
Also of interest: http://php.net/manual/en/language.oop5.decon.php
For codeIgniter 3 I modified Wesley Murch's answer to this
// Create file application/core/MY_Controller.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
$CI = & get_instance();
$CI->load->library('session');
$CI->load->helper('url');
if ( !$this->session->userdata('logged_in'))
{
redirect('login');
}
}
}
Then in any controller to check authorization I used
class News extends MY_Controller {
//code here
}
If you use modules and different sessions for website users and admin users, you can use this code to perfectly redirect them to different login pages-
function __construct() {
parent::__construct();
$CI = & get_instance();
$CI->load->library('session');
$CI->load->helper('url');
// echo "<pre>";print_r($this->router);echo "</pre>";
/**
* if webmaster then check admin session else check user session
* But there may be some classes's method that doesn't requires login hence it is also need to check if
* current request is for those methods before checking session
*/
//to use $this->config->item('webmaster_name') this you have to define
// $config['webmaster_name'] = "webmaster"; in config.php file
if ($this->router->module == $this->config->item('webmaster_name')) {
if (!$this->session->userdata('admin')['id']) {
redirect($this->config->item('webmaster_name').'/login');
}
} else {
if (!$this->session->userdata('user')['id']) {
redirect('login');
}
}
}
If you also want users to allow to access some methods from any particular controller without being logged in you can use this code -
function __construct() {
parent::__construct();
$CI = & get_instance();
$CI->load->library('session');
$CI->load->helper('url');
//echo "<pre>"; print_r($this->router);echo "</pre>"; //_pr($this->config->item('excluded_auth'));
/**
* if webmaster then check admin session else check user session
* But there may be some classes's method that doesn't requires login hence it is also need to check if
* current request is for those methods before checking session
*/
if ($this->router->module == $this->config->item('webmaster_name')) {
if (!$this->session->userdata('admin')['id']) {
redirect($this->config->item('webmaster_name') . '/login');
}
} else {
if (array_key_exists($this->router->class, $this->config->item('exclude_auth')) && in_array($this->router->method, $this->config->item('exclude_auth')[$this->router->class])) {
//echo "escape this method. don not validate for a session";
} else {
if (!$this->session->userdata('user')['id']) {
redirect('login');
}
}
}
}
Note: You can define a custom config file for defining your excluded methods like as-
//save file in application/config/without_auth_methods.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$config['exclude_auth']['news'] = array('index', 'view');
$config['exclude_auth']['users'] = array('index');
I use this function:
Then just call $this->isAuthorized from your controllers __construct.
It allows me to control what controllers are accessed and what methods are accessed too.
protected function isAuthorized()
{
switch ( strtolower( $this->router->class ) )
{
case 'pages':
$disallowLoggedOut = array( 'dashboard' );
$disallowLoggedIn = array( 'index' );
break;
case 'users':
$disallowLoggedOut = array( 'logout' );
$disallowLoggedIn = array( 'register', 'login' );
break;
}
if ( $this->session->userdata( 'loggedIn' ) )
{
if ( in_array( $this->router->method, $disallowLoggedIn ) )
{
redirect( 'pages/dashboard' );
}
}
else
{
if ( in_array( $this->router->method, $disallowLoggedOut ) )
{
redirect( 'pages/index' );
}
}
}
Best way to deal such issue is to create a custom helper that should be called in every method of controller class e.g
Go to application/helpers and create a file login_helper.php
Paste the following code in the helper
<?php
defined('BASEPATH') OR exit('no direct access');
function isLogin($sessionType)
{
if(empty($_SESSION[$sessionType]))
redirect(base_url('loginURL'));
}
?>
Now load this helper into Controller's constructor.
application/controllers/Access.php
this way
defined('BASEPATH') OR exit('access denied');
class Access Extends CI_Controller
{
funcrion __construct()
{
parent::__construct();
$this->load->helper('login');
}
function home()
{
isLogin();
$this->load->view('home_page);
}
}