Which method is used to store cookie data into session file - php

I am using a small PHP framework.
When calling session_start(), a class implementing SessionHandlerInterface
allows a creation of the cookie file throught its method read($id).
A file like sess_533stse23wsdd23rs is created on disk. Good.
Eventually a further call to the SessionHandlerInterface implementation writes more information in the cookie server file. This information can be viewed on call to write($id, $data).
When debugging, I break in the write method implementation and view the call stack and see a call from session_write_close(). I cannot discover where the data passed as parameter to the write is coming from. I do not seem to have this info from the debugger. This type of information is not accessible:
session_write_close(){
// Where this $data is coming from ?
handler...write( $id, $data )
}
In PHP, is there a method to save information to the cookie, so that a call to the session_write_close() will flush this information to the persistent file on disk ?

Ok, finally, from what I discovered, it seems that any data in $_SESSION will be flushed to the cookie file.
Can I get somebody's confirmation ?

Related

Avoid session timeout reset when sending ajax request

Is it possible to tell codeigniter to skip session timeout reset if post request is coming via ajax to a particular controller function. I have a frequent ajax call inside user login dashboard to check something, but these calls keeps the session alive so even if the user stays inactive for 10 minutes (sess_expiration time) session wont be killed and they still remain logged in for ever.
If (and only IF) your Ajax call is completely session-agnostic (that is, it doesn't required to be logged in to run, it doesn't need any session data from the user, etc) you could serve the Ajax request from a separate ajax-specific controller and then inhibit the session library autoload when that specific controller is used.
If the ajax call requires a logged in user you're mostly out of luck.
However, if you meet these conditions, find the $autoload['libraries] section in application/config/autoload.php and use this dirty hack:
// Here, an array with the libraries you want/need to be loaded on every controller
$autoload['libraries'] = array('form_validation');
// Dirty hack to avoid loading the session library on controllers that don't use session data and don't require the user to have an active session
$CI =& get_instance();
// uncomment the one that fits you better
// Alternative 1: you only have a single controller that doesn't need the session library
// if ($CI->router->fetch_class() != 'dmz') array_push($autoload['libraries'], 'session');
// END alternative 1
// Alternative 2: you have more than one controller that doesn't need the session library
// if (array_search($CI->router->fetch_class(), array('dmz', 'moredmz')) === false) array_push($autoload['libraries'], 'session');
// END alternative 2
In the above code, dmz and moredmz are my two imaginary controller names that require the session library to not be loaded. Whenever these are NOT used, the session library is pushed into autoload and thus loaded. Otherwise, the session library is ignored.
I actually have this running on one of my sites in order to allow the health checks from my loadbalancer to run (once every 5 seconds on each application server, from both the primary loadbalancer and its backup) and fill up my sessions table with useless data and works like a charm.
Not sure what version of CI you're using, but the above code is tested on CI 3.1.11.
Now, as you state the Ajax call requires the session driver, the only way around this would be to mess a little with the Session driver itself. In 3.1.11, the session driver is located in system/libraries/Session/Session.php and the part you'd need to change is the final part of the constructor method (look from line 160 onwards). For this example, I'll assume your Ajax calls are handled by a specific controller called "Ajax"
// This is from line 160 onwards
elseif (isset($_COOKIE[$this->_config['cookie_name']]) && $_COOKIE[$this->_config['cookie_name']] === session_id())
{
$CI =& get_instance();
$new_validity = ($CI->router->fetch_class() !== 'ajax') ? time() + $this->_config['cookie_lifetime'] : $_SESSION['__ci_last_regenerate'] + $this->_config['cookie_lifetime'];
setcookie(
$this->_config['cookie_name'],
session_id(),
(empty($this->_config['cookie_lifetime']) ? 0 : $new_validity),
$this->_config['cookie_path'],
$this->_config['cookie_domain'],
$this->_config['cookie_secure'],
TRUE
);
}
$this->_ci_init_vars();
log_message('info', "Session: Class initialized using '".$this->_driver."' driver.");
In a nutshell, this example (haven't tested it so please do before deploying it, it may have a typo or two) will first instantiate the CI core and get the controller name from the Router. If it's a regular controller, it'll determine the new cookie validity as "now plus the cookie validity from the config". If it's the ajax controller, the cookie validity will be the same as the current validity (last regeneration time plus cookie validity.. had to reiterate it as the ternary operator requires it)
Afterwards, the setcookie is modified to use the pre-computed cookie validity depending on what the _config['cookie_lifetime'] value is.

Cannot read cookie data from Cakephp phpunit test

I'm using Cakephp's build in test framework to test my controllers. I have a logout function that expires a variety of cookies that are created as the user uses the site. I am trying to read said cookies to determine if a test should pass or not, i.e. to test if the cookie is correctly expired. I have made sure that the cookie component is correctly instantiated, but I cannot read any value back from the cookie that should be there. This is the code that composes the test I am running:
public function testLogout() {
// setup the cookie component
$collection = new ComponentCollection();
$this->Cookie = new CookieComponent($collection);
$result = $this->testAction('/users/logout');
$cookie_name = Configure::read('tech_cookie_name');
$cookie_data = $this->Cookie->read($cookie_name);
debug($cookie_name);
// cookie data is returning as NULL but I'm expecting some type of value.
debug($cookie_data);
debug($result);
exit;
}
I realize that exit is killing the test early, but I'm using it to see if anything is send back from the cookie. I'm not sure why I cannot read any data from a cookie that I know is there. Does anyone know why that might be, or have a solution for how to properly read from cookies in a unit test.
You cann't read from routes.php Configure::read() in certain cases and it is not a good practice. it will work in localhost but not in live. try to configure your session properly.
by calling your session from AppController and also from your current Controller (UserController) then you should be able to see it in your testing actions.
public $components = array('Session', 'RequestHandler', 'Cookie', ...);
if you write your session like this:
$this->Session->write('Test.tech_cookie_name', 'tech_cookie_name');
then you should be able to read it like this:
$this->Session->read('Test.tech_cookie_name');

Laravel sessions not available in native PHP?

New to Laravel and having some problems with Sessions. Specifically, reading session data from a PHP file outside of Laravel.
For example, let's say I set the session variable like so: Session::put('isAuthorized', 'yes') - I can retrieve this just fine in the Laravel context with Session::get('isAuthorized') but the following PHP will not retrieve this session key -
<?php
session_start();
echo $_SESSION['isAuthorized'];
?>
returns
Notice: Undefined index: isAuthorized in C:\xampp\htdocs\session.php on line 3
I have tried setting the Laravel session driver to both the default cookie and file modes, same result.
You could also write a session adapter, so the $_SESSION variable will be an instance of it:
<?php
class SessionAdapter implements \ArrayAccess {
public function offsetExists($offset) {
return Session::has($offset);
}
public function offsetGet($offset) {
return Session::get($offset);
}
public function offsetSet($offset, $value) {
return Session::put($offset, $value);
}
public function offsetUnset($offset) {
return Session::forget($offset);
}
}
And then somewhere in your code:
<?php
$_SESSION = new SessionAdapter();
// or
$GLOBALS['_SESSION'] = new SessionAdapter();
This way native PHP session and Laravel session will be "the same".
Laravel uses storage drivers for its sessions, namely cookie, file, database, memory, memcached and redis (and APC in Laravel 4).
The web is a stateless environment. This means that each request to your application is considered unrelated to any previous request. However, sessions allow you to store arbitrary data for each visitor to your application. The session data for each visitor is stored on your web server, while a cookie containing a session ID is stored on the visitor's machine. This cookie allows your application to "remember" the session for that user and retrieve their session data on subsequent requests to your application.
http://laravel.com/docs/session/config
The default storage driver is Cookie, so try this:
print_r($_COOKIE);
Please note that this answer is specific to Laravel 3
Laravel doesn't use PHP sessions, so forget session_start(), $_SESSION, etc.
If you're running with file session driver, the session data is stored in a file in storage/sessions. You can obtain the name of the file by reading the Laravel session ID from the cookie. So the hacky way to solve your problem would be to write some code that obtains the session ID from the cookie and then looks for the file with that name in the storage/sessions folder, read that file in, json_decode() it and you can read the whole thing.
If you're running with cookie session driver, all of the session data is stored in the cookie, but it is encrypted, so you'd have to have a copy of the key (which should be in application/config/application.php) and then figure out what encryption method Laravel is using so you can decrypt it. Then you can read all the session variables.
To achieve what you're hoping to achieve - that is, figure out if the current person is authorized, it might be better to build an API into your app and secure it so that it can only be accessed by localhost. Not a great solution from a performance standpoint, but potentially more elegant because you're not hacking around with the internals of Laravel session management.
Session handling in Laravel is indeed different from native PHP session. To use native PHP session, set the value as below:
<?php
session_start();
$_SESSION['isAuthorized'] = 'yes';
echo $_SESSION['isAuthorized']; // output yes
?>

See Objects of a class in php

How can i see How many objects of a class are loaded in php. Also do the objects get loaded in a single session on server? Or one can track objects from other sessions also while on the server side?
Actually i am confused. When an object is loaded with the PHP where does it reside? Is it in the browser? Is it in the session and expires as soon as the session expire?
Will this help?
<?php
class Hello {
public function __construct() {
}
}
$hello = new Hello;
$hi = new Hello;
$i = 0;
foreach (get_defined_vars() as $key => $value) {
if (is_object($value) && get_class($value) == 'Hello')
$i++;
}
echo 'There are ' . $i . ' instances of class Hello';
How can i see How many objects of a class are loaded in php.
I don't think there is a way to do this without you actually keeping count in the class's constructor.
When an object is loaded with the PHP where does it reside? Is it in the browser? Is it in the session and expires as soon as the session expire?
It resides inside the memory that the PHP process that gets called for that one request allocates. It expires as soon as the current request has finished or been terminated (or been unset()).
The session is something that helps identify a user across multiple requests. It survives longer - it expires when it gets destroyed, when the user's session cookie is deleted, or when the session reaches its expiry time.
An object is just a complex variable. It can hold a couple of simple types together and it can have functions.
Despite the numerous differences between simple types and objects, an objects is just a variable. Objects are not shared over sessions, or sent to browsers any more than simple integers or strings.
An object exists only on the server, in memory, and only for the lifetime of the script's execution unless saved into the user's $_SESSION. Even when saved, it ceases to be an object and instead becomes a serialized string. It can be reconstituted again into an object in the same session or a later session.
The script's lifetime refers to the moment the web server calls it until the moment the scripts final line has been processed. The PHP engine may dispose of objects no longer needed by the script through garbage collection, even before the script has fully terminated.

Why can't I store a PHP class instance as a SESSION variable

I have a PHP script that is called in 2 ways from a Dojo Ajax xhrGet call.
The first time it is called with an "init" argument which causes the script to create an instance of the StateList class and read in a file of state names.
session_start();
#include('StateList.php');
require_once('phplog.php');
//start executing here
$comd=$_GET['nexturl'];
if($comd=="init") {
$st = new StateList("../data/statestxt.txt");
$_SESSION['statefile'] = $st;
}
The second and further times, another xhrGet call passes a "getstate" argument and the following code tries to get the instance ofr the StateList class from the SESSION array.
if($comd =="getstate") {
$st= $_SESSION['statefile'];
phplog("size=".$st->getSize());
}
However, the getSize() method is never executed, nor can I call any other method
on the reconstituted StateList class instance.
Note that this is one PHP script that DOES include the class definition at the top
and thus the class methods should be known and avaialble.
What am I missing here?
You need to include the class definition before you call session_start(), otherwise the object will not be deserialized correctly and will be an instance of __PHP_Incomplete_Class. Otherwise what you have should work fine.
You may need to serialize the $st object/variable before you store it. This will ensure that everything is saved to the session. This is definitely the way to go for object oriented code. When you want to use the data again, you must unserialize it.
This is one of those things that's hard to debug in isolation. Storing instantiated objects in PHP Sessions is always a little tricky, and not 100% guaranteed to work. Here's some general debugging tips that may help you figure this out.
First, check your apache error log. Are you getting a "method called on non-object error"? If so, this means you're not getting an object back out of the session. If not, is there an error that indicated your method call is failing for another reason?
Second, check to see what you're really getting out of your session.
if($comd =="getstate") {
$st= $_SESSION['statefile'];
//get the class of st
phplog("instance=".get_class($st));
//get a reflection dump of st
$ref = new ReflectionClass($st);
$string = $ref->__toString();
phplog("reflection=".$string);
}
Third, look at the serialized string value that is being stored in the session itself. Are you actually storing a serialized object? In your dev environment, set the session.save_path ini value in php.ini to something like /tmp, (or use the ini_set method to do the same thing):
session.save_path = "/tmp"
and then examine the files created in /tmp (or whatever folder). You should see a string that starts with:
statefile:O:..........
The name of the class that instantiated the object will also be included in there, as well as values saved to properties.
If you are going to store an object in the session it must be link text.There are a LOT of problems with serializing objects in PHP, let alone storing them in the session. I recommend against doing this altogether, and finding a different solution for your problem. If you are going to do it though, you should look into the 'magic methods' link text which you should define in your class to facilitate it's reinstantiation when it is called from the session.
Do you have session.auto_start enabled? The manual's session page states that if you do, you have to load the class definition differently:
If you turn on session.auto_start then the only way to put objects into your sessions is to load its class definition using auto_prepend_file in which you load the class definition else you will have to serialize your object and unserialize it afterwards.
http://php.net/manual/en/intro.session.php
As that page says, the serialization/unserialization of the object will normally be done automatically by PHP, but having session.auto_start enabled will change this.
Try this:
include('StateList.php');
require_once('phplog.php');
// start your session after including your class file
session_start();
//start executing here
$comd=$_GET['nexturl'];
if($comd=="init") {
$st = new StateList("../data/statestxt.txt");
$_SESSION['statefile'] = $st;
}
if($comd =="getstate") {
// the ampersand creates a reference, preserving any further changes to your session data
$st = &$_SESSION['statefile'];
phplog("size=".$st->getSize());
}

Categories