Cannot retrieve session id using session class in CodeIgniter - session

i have this code in my controller
class Upload_center extends Controller
{
function __construct()
{
parent::Controller();
$this->load->model('auth_model') ;
if(!$this->auth_model->authorize())
{
redirect('login');
}
}
and I have this code in my view
$('#swfupload-control').swfupload({
upload_url: "<?=base_url()?>index.php/upload_center/upload",
file_post_name: 'fileupload',
file_size_limit : "200000000",
file_types : "*.zip;*.rar;*.pdf;*.doc;*.docx;*.mp3;*.avi;*.wmv;*.docx;*.jpg;*.jpeg;*.JPG;*.JPEG;*.png;*.gif;*.bitmap;",
file_types_description : "zip files ",
post_params: {"PHPSESSID": "<?=$this->session->userdata('session_id');?>"} ,
file_upload_limit : 1,
flash_url : "<?=base_url()?>js/jquery-swfupload/js/swfupload/swfupload.swf",
button_image_url : '<?=base_url()?>js/jquery-swfupload/js/swfupload/wdp_buttons_upload_114x29.png',
button_width : 114,
button_height : 29,
button_placeholder : $('#button')[0],
debug: false
I want the user to upload their files after login, so I have a method that needs users to login before proceeding to upload files. Although I'm using flash uploader in my view, I think it doesn't pass the session value and PHP thinks the user is not logged in and it redirects him to the login page. I send phpsessionid by post but still no goes.

What's your session cookie expiration set to? There is a known bug in CodeIgniter where, if you stay on a page that makes AJAX requets past the cookie expiration, it will reset the session id in the database, but will not be able to set it in the browser cookie because it's an asynchronous request. This causes there to be a disconnect on the next non-asynchronous GET request, leading to the session library calling sess_destroy(). If this sounds like your situation, let me know. Otherwise, provide more detail, please.
Edit: I should, perhaps, also include the fix for this bug here. Create a file in /application/libraries called "MY_Session.php" (if it doesn't already exist). In there you can paste this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* Session Class Extension
*/
class MY_Session extends CI_Session {
/*
* Do not update an existing session on ajax calls
*
* #access public
* #return void
*/
function sess_update() {
if ( !isAjax() ){
parent::sess_update();
}
}
}
?>
That isAjax() function is a helper I have in /application/helpers/isajax_helper.php that looks like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* is_ajax_call
*
* Determines if the current page request is done through an AJAX call
*
* #access public
* #param void
* #return boolean
*/
if ( ! function_exists('isAjax')) {
function isAjax() {
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
}
}
?>
Which is referenced in my config file like this:
$autoload['helper'] = array('otherhelper1', 'isajax', 'otherhelper2');

By default, CI creates a new sessionid in a defined interval. Look at the config to see the default value (I believe it's 5 minutes). So $this->session->userdata('session_id') will always contain a different ID but CI still is able to know who you are.
I ran into the problem for the exact same reason. I know why the CI guys created this session refreshment but I feel like it is making things more complex. You can override this behaviour in your config by simply entering a higher value for the session refresh.
In one of my apps, it looks like this:
$config['sess_expiration'] = 7200;
//$config['sess_time_to_update'] = 300;
$config['sess_time_to_update'] = $config['sess_expiration'];
This way, I'm able to use sessions as I would do without the framework.

not possible. The Session class does not utilize native PHP sessions.
best practice I recommend you
contoller contain uploadpage {
function index(){
$dataview['session_id'] = $this->secureUpload();
$this->load->view('upload',$dataview);
}
function secureUpload(){
$user_id = $this->session->userdata('cuser_id');
$md5pass = $this->basemodel->_getEncrypPassFromDb($user_id);
$time =time();
$session = md5($user_id.$time.$md5pass)."x".$user_id."x".$time;
return $session;
}
}
upload page
('#swfupload-control').swfupload({
post_params: {"PHPSESSID": "<?=session_id?>"} ,
this way decryp you secure code
function upload_function(){
list($session2, $user_id, $time) = explode("x", $session);
$this->load->library('upload', $config);
$md5pass = $this->basemodel->_getMD5pass($user_id);
$session_server = md5($user_id.$time.$md5pass)."x".$user_id."x".$time;
if($session_server == $session){
upload file by flash upload
}
}

I was just having this problem, ajax calls destroying my logged in user session. Here's #treeface solution with CI 2.1.2 per Mr. Sturgeon's suggestion. I guess the input and load libraries are not autoloaded in CI_Session, so I had to get the instance of the CI object to make this work.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* Session Class Extension
*/
class MY_Session extends CI_Session {
protected $_CI;
/*
* Do not update an existing session on ajax calls
*
* #access public
* #return void
*/
function sess_update() {
$this->_CI =& get_instance();
if ( !$this->_CI->input->is_ajax_request() ){
parent::sess_update();
}
}
}

I think you should see this
http://ellislab.com/forums/viewthread/138823/
It explains to get rid of the problem

Related

How can I change SMTP details globally at runtime?

I'm using Laravel 5.5. The nature of the website is a 'multisite' architecture where multiple websites/domains are run from the same codebase.
I've come across an issue when sending email. I need to change the from name and address as well as the transport (SMTP, etc) options depending on which website is being viewed. I have these details stored in a config file.
The easiest way is to just pull those details in the Controller before I call Mail::send/Mail::queue and to update them. However, this brings back 2 issues:
There is a heavy reliance on remembering to actually do that every time I send any email in the code. In short, it's not abiding by DRY.
I'd be forced to use Mail::send instead of Mail::queue, because the queue wouldn't have any idea of the config update from the time it was queued only from when it is processed .
How can I achieve what I am looking to do here in a clean way?
I thought about extending all of my 'Mailable' classes with a custom class that updates the SMTP details, but it doesn't look like you can update the SMTP/Transport information after the class is initiated; you can only update the from name and address.
I managed to find a way to do this.
I had my mailable class (ContactFormMailable) extend a custom class, as follows:
<?php
namespace CustomGlobal\Mail;
use CustomGlobal\Mail\CustomMailable;
use CustomGlobal\ContactForm;
class ContactFormMailable extends CustomMailable
{
public $contact_form;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(ContactForm $contact_form)
{
$this->contact_form = $contact_form;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$view = $this->get_custom_mail_view('contact_form', $this->contact_form);
return $this->subject('Contact Form Enquiry')
->view($view);
}
}
You'll notice I'm calling get_custom_mail_view. This is in my extended class and used to calculate the view and template I need to use for my mail, depending on the website being viewed. In here I also set the location of my config folder.
<?php
namespace CustomGlobal\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use Swift_Mailer;
use Swift_SmtpTransport;
use CustomGlobal\Website;
use CustomGlobal\Territory;
class CustomMailable extends Mailable
{
use Queueable, SerializesModels;
public $layout_view_to_serve;
public $host_folder;
/**
* Override Mailable functionality to support per-user mail settings
*
* #param \Illuminate\Contracts\Mail\Mailer $mailer
* #return void
*/
public function send(Mailer $mailer)
{
app()->call([$this, 'build']);
$config = config($this->host_folder .'.mail');
// Set SMTP details for this host
$host = $config['host'];
$port = $config['port'];
$encryption = $config['encryption'];
$transport = new Swift_SmtpTransport( $host, $port, $encryption );
$transport->setUsername($config['username']);
$transport->setPassword($config['password']);
$mailer->setSwiftMailer(new Swift_Mailer($transport));
$mailer->send($this->buildView(), $this->buildViewData(), function ($message) use($config) {
$message->from([$config['from']['address'] => $config['from']['name']]);
$this->buildFrom($message)
->buildRecipients($message)
->buildSubject($message)
->buildAttachments($message)
->runCallbacks($message);
});
}
/**
* Calculate the template we need to serve.
* $entity can be any object but it must contain a
* $website_id and $territory_id, as that is used
* to calculate the path.
*/
public function get_custom_mail_view($view_filename, $entity)
{
if(empty($view_filename)) {
throw new Exception('The get_custom_mail_view method requires a view to be passed as parameter 1.');
}
if(empty($entity->website_id) || empty($entity->territory_id)) {
throw new Exception('The get_custom_mail_view method must be passed an object containing a website_id and territory_id value.');
}
// Get the website and territory
$website = Website::findOrFail($entity->website_id);
$territory = Territory::findOrFail($entity->territory_id);
$view_to_serve = false;
$layout_view_to_serve = false;
// Be sure to replace . with _, as Laravel doesn't play nice with dots in folder names
$host_folder = str_replace('.', '_', $website->website_domain);
$this->host_folder = $host_folder; // Used for mail config later
/***
Truncated for readability. What's in this area isn't really important to this answer.
***/
$this->layout_view_to_serve = $layout_view_to_serve;
return $view_to_serve;
}
}
It's important to remember that mail can be queued. If you do this is another way, such as setting a config at runtime, then you'll find that the process that runs the queue has no visibility/scope of your runtime config changes, and you'll end up firing out email from your default values.
I found a few answers similar to this one, which helped me out, but none of them worked completely, and some are out-dated (Swift_SmtpTransport is changed considerably since those answers).
Hopefully this helps someone else out.

How do I access non id property of request inside form requests?

I want to access route request parameters inside laravel form requests authorize. I cant find an example describing this.
// Works fine when you want id
dd($this->route('myResourceName'));
// How to do when I want something else???
dd($this->route('anotherAttribute'));
// Above give null probably because it is a resourceful controller
On a side note, I dont understand this design, whats the point?
$this->route('anyAttribute') would be the easiest, right?
Edit: more extensive example
class UpdateSlotAPIRequest extends APIRequest
{
public function __construct(){
parent::__construct();
$this->slot = Slot::find($this->route('slot'));
$this->access_token = $this->route('access_token'); // this is not working!
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// If administrator is logged in all is good.
// If slot is free its ok.
// If its not free but you provide good access_token its also fine.
return Auth::check() || $this->slot->isAvailable() || $this->slot->isValidAccessToken($this->access_token);
}
...
```
$access_token = request()->input('access_token');
Found it in https://laravel.com/docs/5.4/helpers

How to redirect to the method of a controller after user doing authentication on codeigniter?

I am using the Default Controller to make the user authentication. What I am trying to do is whatever is the page the user request news/add or news/index or themes/all or maps/view, if he is not logged in, he or she will be directed to the log in page and then redirected to the page he wanted to go, not always the same page.
You can your the
CodeIgniter User Agent Library and Session Library to store and use the referring url. The user agent library is basicly accessing the $_SERVER['HTTP_REFERER'] value.
NOTE: from the php.net website:
Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.
so this is not a foolproof method.
if ($this->agent->is_referral()) {
$this->session->set_userdata('prev_url', $this->agent->referrer());
}
// later, when login is successful
$prev_url = $this->session->userdata('prev_url');
if( $prev_url ) {
redirect($prev_url);
}
one way is to do it in the constructor of your controller. that way they are redirected before going to the news/add etc.
so for example you create a model called "sentry" and a "getUser()" method to check the browser cookie to see if the user is authorized. if they are not authorized have it return false. if they are authorized have it return $user so then you have it available for your other methods.
function __construct() {
parent::__construct();
$this->load->model( 'sentry' );
if ( ! $this->user = $this->sentry->_getUser() )
{ redirect( '/login/', 'refresh' ); }
}
so then for example you could have $this->user->name etc etc available to any method in the controller. And $this->user will also automatically be available in all the view files of this controller.
I do this by extending my controller and I check in constructor if person is logged in or not, if person is logged in I save to the session current URL, and redirect person to the login page (if same constructor is applied (controller one) I make exception to not save current URL to the session) after logging in I call redirect function to the session variable.
How to extend your controller is done here http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-Base-Classes-Keeping-it-DRY
note that when your controller is extended you use $this->data['variable_sent_to_view'] and you can omit second parameter of $this->load->view()
here is some example code assuming you know how your login controller works
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Controller extends CI_Controller {
function __construct() {
parent::__construct();
$this->output->enable_profiler(FALSE);
if ($refer = $this->session->flashdata('refer')) {
$this->data['refer_page'] = $refer; // $this->data['refer_page'] is variable that you are interested in
unset($refer);
} else {
$this->data['refer_page'] = base_url(); //default refer_page
}
//check if user is NOT logged in
if (!$logged_in) {
$this->_setRefer(); //this is private function
}
// else dont care about it
}
private function _setRefer() {
$invalid_method = array('search', 'login'); // if method is 'search' or 'login' url will not save in session (it will stay same as was before)
$valid_refer = TRUE;
if (in_array($this->router->method, $invalid_method)) {
$valid_refer = FALSE;
}
if (!(count($_POST) > 0) && $valid_refer === TRUE && !$this->input->is_ajax_request()) {
$this->session->set_flashdata('refer', current_url());
} else {
$this->session->set_flashdata('refer', $this->data['refer_page']);
}
}
}
now in after succesful login redirect to $this->data['refer_page'], but note that login controller must by extended by MY_Controller.
this script also takes care about what happens if user made mistake and inserted wrong password (page will reload but "old" url stays)

why my joomla controllers method is not getting executed

I have an ajax method which sends data to one of my controller but the method inside of my controller is not getting fired. Everytime the first method is getting executed on call. The controller looks as it follows
class TieraerzteControllerUploader extends JController
{
/**
* display task
*
* #return void
*/
function display($cachable = false)
{
require_once JPATH_COMPONENT_ADMINISTRATOR.'/helpers/upload.php';
$upload_handler = new UploadHandler();
//this one is going to be outputed
die();
}
public function locator(){
// I wait here for a dump, but is not happening
var_dump('test');
die();
echo '{"text":"John Smith","id":"433"},{"text":"Paul Sparks","id":"434"}';
}
}
I call the controller with the following url
/administrator/index.php?option=com_tieraerzte&task=uploader.locator&tmpl=component&q=search
even if I call the above url the result is the same
I think you are using wrong formated joomla url.
Try this url formate,u may call the controller
index.php?option=com_tieraerzte&view=uploader&tmpl=component&q=search
watch the difference between your url and my url.

Codeigniter Call Controller From Controller

After the last two comments, I'll dump out my real code and maybe it will help out:
Here is the landing Controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Businessbuilder extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
$RTR = $GLOBALS["RTR"];
// import the necessary libraries
$this->load->model("site_pages");
$RTR = $GLOBALS["RTR"];
// get the current site
$site = current_site();
// get the requesting url
$class = $RTR->uri->rsegments[1];
$function = $RTR->uri->rsegments[2];
// get the current function and class
$current_method = explode("::", __METHOD__);
// get the real class name that is going to be called
$site_page = $this->site_pages->get(array("display_name"=>$class, "id"=>$site->id));
$site_page = $site_page->result();
if(count($site_page) == 1)
{
$site_page = $site_page[0];
// set the class name to be called
$class = $site_page->class_name;
}
// only execute if the requested url is not the current url
if(!(strtolower($class) == strtolower($current_method[0]) && strtolower($function) == strtolower($current_method[1])))
{
if(!file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$class.EXT))
{
show_404($RTR->fetch_directory().$class);
exit;
}
// include the required file. I use require once incase it is a file that I've already included
require_once(APPPATH.'controllers/'.$RTR->fetch_directory().$class.EXT);
// create an instance of the class
$CI = new $class();
if(method_exists($CI, $function))
// call the method
call_user_func_array(array(&$CI, $function), array_slice($RTR->uri->rsegments, 2));
else
{
show_404($RTR->fetch_directory().$class);
exit;
}
}
}
}
here is an example of a dynamic controller that will be called:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Public_homepage extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
echo "<br /><br /><br />";
$this->load->model("sites");
$style = $this->sites->get(array("id"=>1)); // fail here, sites not defined
//print_r($style);
exit;
$view_params = array();
$view_params["site_id"] = $this->site_id;
$this->load->view('public_homepage', $view_params);
}
}
Here is my model that I am using:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Sites extends CI_Model
{
function __construct()
{
parent::__construct();
}
function get($search = array())
{
return $this->db->query("SELECT * FROM sites"); // failure on this line, db undefined
}
}
the error that I am getting is either this (error1):
A PHP Error was encountered
Severity: Notice
Message: Undefined property: Public_homepage::$sites
Filename: controllers/public_homepage.php
Line Number: 15
Fatal error: Call to a member function get() on a non-object in /var/www/businessbuilderapp.com/public_html/application/controllers/public_homepage.php on line 15
or this (error2):
A PHP Error was encountered
Severity: Notice
Message: Undefined property: Businessbuilder::$db
Filename: core/Model.php
Line Number: 50
Fatal error: Call to a member function query() on a non-object in /var/www/businessbuilderapp.com/public_html/application/models/bba_model.php on line 25
My theory as to why I am getting these errors is because the instance of the object is different than the one that loaded the model and libraries. What's odd about that though is that arrays are carried over, but not objects. So in the core Loader.php of codeigniter array $_ci_models is populated with models that are not loaded in the Public_homepage class
Also what might help you is that from the first pass through the businessbuilder class, I am able to load and use the modules successfully, but when Public_homepage is called, that's when things start to fail.
What makes this confusing is that I'm trying to figure out 2 errors with one question which is probably my mistake. Here is a description of when I get the errors:
Error1:
When I run the code as is, I cannot call the sites property.
Error2:
When I change the
call_user_func_array(array(&$CI, $function), array_slice($RTR->uri->rsegments, 2));
to
eval($class . "->" . $function);
I understand that this is really confusing, especially when I explain it, but if you need more info, please let me know. Also note that the Public_homepage looks like that because I am testing. There's no need to dump more useless lines if the error can be produced with minimal code.
Update
After reading some of the answers, I realized that I didn't explain the code. What this code does is that it allows me to store different urls inside a database, but all the urls stored there can call the same page even though they are different. I guess an exact example would be changing the slug on wordpress.
What happens is that the businessbuilder class is set to accept ALL requests to the server. When it hits the businessbuilder class, it will access the database, find out what sub url you are using, find the real controller that the user is looking for, and access that controller.
So after lots of searching, I think I have a workaround. The issue what what I thought with the instance. After diving into the framework I realized that it is storing the instance into as static var, private static $instance. I modified the constructor to not overwrite if that var has been populated. On top of that, since there were some oddities still with the loading, for some reason objects would be marked as loaded but in reality were not, I had to add a new var to the controller, protected $ci_instance. In the end, I modified the CI_Controller to look like the following:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* CodeIgniter
*
* An open source application development framework for PHP 5.1.6 or newer
*
* #package CodeIgniter
* #author ExpressionEngine Dev Team
* #copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
* #license http://codeigniter.com/user_guide/license.html
* #link http://codeigniter.com
* #since Version 1.0
* #filesource
*/
// ------------------------------------------------------------------------
/**
* CodeIgniter Application Controller Class
*
* This class object is the super class that every library in
* CodeIgniter will be assigned to.
*
* #package CodeIgniter
* #subpackage Libraries
* #category Libraries
* #author ExpressionEngine Dev Team
* #link http://codeigniter.com/user_guide/general/controllers.html
*/
class CI_Controller {
private static $instance;
protected $ci_instance; // line added
/**
* Constructor
*/
public function __construct()
{
if(self::$instance == null) // line added
self::$instance =& $this;
$this->ci_instance =& get_instance(); // line added
// Assign all the class objects that were instantiated by the
// bootstrap file (CodeIgniter.php) to local class variables
// so that CI can run as one big super object.
foreach (is_loaded() as $var => $class)
{
$this->$var =& load_class($class);
}
$this->load =& load_class('Loader', 'core');
$this->load->_base_classes =& is_loaded();
$this->load->_ci_autoloader();
log_message('debug', "Controller Class Initialized");
}
public static function &get_instance()
{
return self::$instance;
}
}
// END Controller class
/* End of file Controller.php */
/* Location: ./system/core/Controller.php */
The only issue so far is that I cannot do $this->load->model("some_model");. Instead I have to use $this->ci_instance->load->model("some_model"); and everything will stem from there. I don't really care about the extra var, but what I don't like is modifying out of box solutions because it increases the complexity to do an upgrade.
for now I've marked this as an answer because it is what "I" have chosen to use as my solution, but I am still opened to a better solution than the one I am using. An exact description of what needs to be solved is as follows:
Copy all loaded properties from one instance to another. Basically do a merger of two instances if possible.
If someone can answer that with a better solution than mine, preferably without modifying the codeigniter core, I'd gladly change my answer because I am not happy with my solution because I don't know what effects I might encounter later on during development.
In your application/autoload.php set codeigniter to load database class.
$autoload['libraries'] = array('database', 'otherlibrary', 'otherlibrary2');
It must be all you need to solve your problem.
if u using HMVC just using
Class Models extends MX_Loader{
function getUser($username){
$sql="SELECT
*
FROM
user
WHERE username = ? "
return $this->db->query($sql,array($username))->row();
}
}

Resources