I am looking for a way to read the contents of a PHP session without actually replacing the running session of the current request.
Lets say I have a running session (started before with session_start(), using the default session handler and the session_id given by the PHPSESSID cookie)
Now I have another (valid) session_id and I want to read some of the data stored in that session.
The only way I can think of is to replace the current session with $oldSession = session_id(), set the new session with session_id($newId), then read the data from $_SESSION and then restart the original session with session_id($oldSession) - probably involving some aditional calls of session_commit() and session_start().
But I prefer to not touch the current, running session at all...
PHP 5.4 introduces the SessionHandler class (http://php.net/manual/de/class.sessionhandler.php) but manually calling $SessionHandler->read doesn't seem to work either
$handler = new SessionHandler();
var_dump($handler->read($session));
//Fatal error: SessionHandler::read(): Cannot call default session handler
I am using the native php memcached session handler
Thank you for any tipps!
I solved the problem by directly reading the session data from memcached.
Code based on a comment from http://php.net/manual/de/memcached.sessions.php
$session = 'session_id_to_read';
$servers = explode(',', ini_get('session.save_path'));
$c = count($servers);
for ($i = 0; $i < $c; ++$i) {
$servers[$i] = explode(':', $servers[$i]);
}
$memcached = new \Memcached();
$memcached->addServers($servers);
$sessionPrefix = ini_get('memcached.sess_prefix');
$rawData = $memcached->get($sessionPrefix.$session);
$data = $rawData ? unserialize($rawData) : false;
note that unserialize($rawData) only works if session.serialize_handler is set to 'php_serialize'
Related
I need to set a dynamic id for every document load. This ID should be set in PHP. Now, when i set a session_start(), the php code would be executed twice because the ID-code in generated document source differs from the same code in the alerted script variable. There are no runtime errors.
What's wrong with this code and how can i prevent the session to re-execute my code after session_start() ?
And when the code would be executed twice (var idvar contains a different value) why the heck is alert executed only once?
I simplified the script so you can try for your self:
<?php
// Session start generates two different ID's
session_start();
// Create ID
$time = microtime(1);
$parts = explode('.', (string)$time);
$idvar = strtoupper(strrev(dechex($parts[0]) . dechex($parts[1]))) . dechex(rand());
?>
<script>
// Contains a new generated ID after session_start()
var IDvr = '<?php print $idvr; ?>';
alert(IDvr);
</script>
Screenshots:
Try move the id initialization just before session_start() i suspect it related on how things executed in php after session_start().
Edit
still unable to reproduce it
I found this:
PHP Session storing behavior into variables?
But even when i add a favicon to the page it don't works. Also the page is standalone and not included as require in another page.
Even this is not working!
// Session start generates two different ID's
if(!isset($_SESSION) && !isset($idvr)) {
session_start();
// Create ID
$time = microtime(1);
$parts = explode('.', (string)$time);
$idvr = strtoupper(strrev(dechex($parts[0]) . dechex($parts[1]))) . dechex(rand());
}
Update:
Now corrected:
With view-source:pgname and session initialized the code would be executed again in source view!
I wan to use CI session in a external script and I got following data from database.
__ci_last_regenerate|i:1446535049;ci_UserID|s:1:"2";ci_UserName|s:24:"example#xyz.com";logged_in|b:1;
I have tried unserialize and unserialize(base64_decode($data)) but I am fail yet.
Please help to extract this data.
I got the solution here
So I have used session decode
session_decode('__ci_last_regenerate|i:1446535049;ci_UserID|s:1:"2";ci_UserName|s:24:"example#xyz.com";logged_in|b:1;');
So session decode stored all the encrypted data in normal php session.
Which I can access using: echo $_SESSION['ci_UserID'];
Well guys thanks for the help
If this is a session variable, you can use CodeIgniter's own session library. Consider the following code (in a controller):
$this->load->library('session'); // load the session library
$session_data = $this->session->all_userdata(); // get all session data
print_r($session_data); // print and get the corrresponding variable name, e.g. "item"
$var = $this->session->userdata('item'); // pick one that suits your needs, e.g. item
Sorry, I have read "the external script" only after having posted the code. This obviously only works in the CI framework.
For an external script you may need to have a closer look. The variables are separated by ";" and "|" and then serialized, so this might work (not tested):
$row = explode(';', '__ci_last_regenerate|i:1446535049;ci_UserID|s:1:"2";ci_UserName|s:24:"example#xyz.com";logged_in|b:1;'); // load the database row
$userid = explode('|', $row[1]);
$userid = unserialize($userid[1]); // now $userid holds the value "2"
I heard the best method to share session across multiple domains on same server is to use custom php session handler. (ie, domain name different like abc.com, xyz.com but single application.)
But after i tried it, even custom php session handler that using SAME DATABASE ON 1 SERVER can't share session, when i tried to read cookie value from different domain.
Here's my custom session handler, Please kindly check or fix if something missing here. because i've tried it for a week now. can't get it to work
P.S. To get previous session id, i use link such as: newdomain.com/?ssid=[SESSION_ID]
SESSION_INCLUDE.PHP
<?php
// config
$m_host = "localhost"; //MySQL Host
$m_user = "db_user"; //MySQL User
$m_pass = "db_pass"; //MySQL Pass
$m_db = "db_name"; //MySQL Database
$table = "sess_data";
$session_expire = 600; // Session expire time, in seconds (minutes * 60 = seconds)
$gc_probability = 100; // Probability that the garbage collection function will be called. 50% chance by default
ini_set("session.gc_probability",$gc_probability);
/* Open function; Opens/starts session
Opens a connection to the database and stays open until specifically closed
This function is called first and with each page load */
function open ($s,$n) // do not modify function parameters
{
global $session_connection, $m_host, $m_user, $m_pass, $m_db;
$session_connection = mysql_pconnect($m_host,$m_user,$m_pass);
mysql_select_db($m_db,$session_connection);
return true;
}
/* Read function; downloads data from repository to current session
Queries the mysql database, unencrypts data, and returns it.
This function is called after 'open' with each page load. */
function read ($id) // do not modify function parameters
{
global $session_connection,$session_read,$table;
$query = "SELECT data FROM `$table` WHERE id=\"{$id}\"";
$res = mysql_query($query,$session_connection);
if(mysql_num_rows($res) != 1) return ""; // must return string, not 'false'
else
{
$session_read = mysql_fetch_assoc($res);
$session_read["data"] = base64_decode($session_read["data"]);
return $session_read["data"];
}
}
function write ($id,$data) // do not modify function parameters
{
if(!$data) { return false; }
global $session_connection, $session_read, $session_expire, $table;
$expire = time() + $session_expire;
$data = mysql_real_escape_string(base64_encode($data));
if($session_read) $query = "UPDATE `$table` SET data=\"{$data}\", expire=\"{$expire}\" WHERE id=\"{$id}\"";
else $query = "INSERT INTO sess_data SET id=\"{$id}\", data=\"{$data}\", expire=\"{$expire}\"";
mysql_query($query,$session_connection);
return true;
}
function close ()
{
global $session_connection;
mysql_close($session_connection);
return true;
}
function destroy ($id) // do not modify function parameters
{
global $session_connection,$table;
$query = "DELETE FROM `$table` WHERE id=\"{$id}\"";
mysql_query($query,$session_connection);
return true;
}
function gc ($expire)
{
global $session_connection,$table;
$query = "DELETE FROM `$table` WHERE expire < ".time();
mysql_query($query,$session_connection);
}
// Set custom handlers
session_set_save_handler ("open", "close", "read", "write", "destroy", "gc");
// Start session
session_start();
?>
MySQL Database Description
create table sess_data (
id2 int not null auto_increment,
id text not null,
data text,
expire int not null,
primary key(id2)
);
You can't read cookies from one domain in another domain. That's a security thing implemented in the browser. Using a database for sessions allows you to have multiple servers share sessions on the same domain, but does not allow for multiple domains on the same server to share sessions.
If you want to share sessions between domains, you would need to implement some sort of session transfer method when you switch domains. The simplest way to do this would involve passing the session id as a GET parameter from a page on one domain to a page on the other. Then, on the other domain, you would pick up the session id and create a new session using that ID.
While that is a simple way to do it, it isn't very secure and allows for session hijacking. A better way would be to use the database to create a record with the session id in it, set a short timeout on it, and pass the ID of that record to the other domain. The other domain would then pick up the record from the database and create a session with it. If the record in the database is past it's expiration, it wouldn't pick up the session. This would provide better protection against session hijacking.
This is the purpose of session_name(). Assign a different name to each application's session to avoid collisions between $_SESSION keys. The name will be used as the session cookie's name so although both session cookies will be passed to both applications, only the one matching the application's session_name() will be used to populate $_SESSION.
// App 1
session_name('app1');
session_start();
// App 2
session_name('app2');
session_start();
You really should look into SSO (single sign-on). One option for SSO is to use OpenID (as used on SO), and using it will make your life a lot easier.
Here's an article on it : http://devzone.zend.com/article/3581
the cookies and their visibility is a problem. The browser accessing the new site would not send the session id of the old site to the server.
I think your read() does not use the ssid parameter you provide as session id but as the browser has no session with this domain the system generates one with new id as $id. Have a look if $_REQUEST['ssid'] exist in the database.
Custom session handler might a bit big for this job. You could just check if $_REQUEST['ssid'] exist in the session database and rewrite $_SESSION with it.
I was wondering if anyone could give some suggestions on my method for sharing sessions between domains on same server (same cookie storage folder).
In each pages HEAD tag on all my sites, I call the following PHP code
if(!isset($_SESSION['sso'])) {
require_once('database.php');
$sites = array('http://site1', 'http://site2');
session_regenerate_id(); //Make new session id that will be shared
$session_id = session_id();
foreach($sites as $site) {
if($site != CURRENT_SITE) {
$sesh_key = md5(SALT.$site.$session_id);
$database->insertSessionId($sesh_key, $session_id);
$url = sprintf('%s/sso_set.php?k=%s', $site, $sesh_key);
echo('<link type="text/css" rel="stylesheet" href="'.$url.'" />');
}
}
$_SESSION['sso'] = 'SET';
}
Then on each site I have a file called 'sso_set.php' which contains
<?php
session_start();
if(!isset($_SESSION['sso'])) {
require_once('database.php');
$key = $_GET['k'];
$session_id = $database->getSessionId($key);
if($session_id) {
session_destroy();
session_id($session_id);
session_start();
$database->deleteSessionId($key);
$_SESSION['sso'] = 'SET';
}
}
Is using a text/css link a good idea?
I figured this is always called even if Javascript or Images are disabled?
This code basically makes the first site out of all my sites that gets opened by the user sets the Session ID, and then passes it on to the other sites.
Seems to work pretty well.
You get a slight delay the very first time any of the sites opened and the ID is passed to the sites. But, you could do this via AJAX so the page loads fast. But, then you rely on Javascript being enabled.
Thoughts?
This question already has answers here:
Check if PHP session has already started
(27 answers)
Closed 1 year ago.
Per request, there are a few different ways that you can tell whether or not a session has been started, such as:
$isSessionActive = (session_id() != "");
Or:
$isSessionActive = defined('SID');
However, these both fail if you start a session, then close it; session_id() will return the prior session's ID, while SID will be defined. Likewise, calling session_start() at this point will generate an E_NOTICE if you already have a session active. Is there a sane way to check if a session is currently active, without having to resort to output buffering, the shut-up operator (#session_start()), or something else equally as hacky?
EDIT: I wrote a patch to try to get this functionality included in PHP: http://bugs.php.net/bug.php?id=52982
EDIT 8/29/2011: New function added to PHP 5.4 to fix this: "Expose session status via new function, session_status"
// as of 8/29/2011
$isSessionActive = (session_status() == PHP_SESSION_ACTIVE);
EDIT 12/5/11: session_status() on the PHP manual.
See edits to the original question; basically, PHP 5.4 and above now has a function called session_status() to solve this problem!
"Expose session status via new function, session_status" (SVN Revision 315745)
If you need this functionality in a pre-PHP 5.4 version, see hakre's answer.
I worked around this by adding a couple wrapper functions around the various session creation/closing/destroying functions. Basically:
function open_session() {
session_start();
$_SESSION['is_open'] = TRUE;
}
function close_session() {
session_write_close();
$_SESSION['is_open'] = FALSE;
}
function destroy_session() {
session_destroy();
$_SESSION['is_open'] = FALSE;
}
function session_is_open() {
return($_SESSION['is_open']);
}
Hackish, but accomplished what I needed.
I'm running into this as well, and a setting in $_SESSION is not an option for me. For PHP 5.3.8:
If any session has been started with the request, define('SID') will return FALSE, as well as $_SESSION is unset.
This is independent whether or not session_id() has been used to set a session id or not.
After the first session_start(), SID is defined and $_SESSION is set to an empty array.
session_destroy() does unset the session_id(), it's an empty string then. SID will remain defined (and set to it's previous value which might be an empty string). $_SESSION is left unchanged. It will get reset/populated next time session_start is called.
With these states, especially as session_id() can be called in between to set the id for the next session, it's not possible to safely determine the session status with SID, $_SESSION and session_id().
"Trying" with session_start() (e.g. with #) might not be really helpful, as this will change the session status and changing the contents of $_SESSION (and adding a set-cookie header if the cookie was not part of the request). It was not fitting in my case.
While I was running tests, I came across the behaviour, that you can not try to change the ini setting of session.serialize_handler when the session is active, not even when you set it to the same value. Same is true for session.use_trans_sidDocs which is more lightweight. This lead me to the following function:
/**
* #return bool
*/
function session_is_active()
{
$setting = 'session.use_trans_sid';
$current = ini_get($setting);
if (FALSE === $current)
{
throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
}
$result = #ini_set($setting, $current);
return $result !== $current;
}
As far as I can see, the error is checking for active session status only (not disabled), so this should not return a false positive when sessions are disabled.
To get this function compatible with PHP 5.2, it needs a little modification:
/**
* #return bool
*/
function session_is_active()
{
$setting = 'session.use_trans_sid';
$current = ini_get($setting);
if (FALSE === $current)
{
throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
}
$testate = "mix$current$current";
$old = #ini_set($setting, $testate);
$peek = #ini_set($setting, $current);
$result = $peek === $current || $peek === FALSE;
return $result;
}
Some sandbox.
The following code only dumps one session_id() for me, not two
session_start();
echo session_id();
session_destroy();
echo session_id();
If you're having difficulties with this still you can try creating a variable to check, that you destroy when you destroy the session.
session_start();
$_SESSION['intialized'] = 'This will not print';
$_SESSION = array(); // Unset all variables
session_destroy();
echo $_SESSION['initialized']; // No output
Here's a good drop in replacement that won't break stuff when you move to 5.4:
if(!function_exists('session_status')){
function session_active(){
return defined('SID');
}
}else{
function session_active(){
return (session_status() == PHP_SESSION_ACTIVE);
}
}
Ken, if the session is destroyed, the $_SESSION array should not be available...or at the very least, your values should be unset. So, in theory (untested) you should be able to check the array for a value to know if anything is currently set.
There are multiple places you need to check to verify the session is active:
1- cookie exists and is not expired
2- underlying session storage mechanism (file system or database) has a record matching the cookie.
I have run into a very interesting problem trying to debug my custom PHP session handler. For some reason unknown to me I can set cookies all the way through the session handler right up until the very start of the write function.
As far as I know session handler calls go in this order.
open -> read -> write -> close
The open function sets a cookie just fine.
function open($save_path,$session_name)
{
require_once('database.php');
require_once('websiteinfo.php');
mysql_connect($sqllocation,$sql_session_user,$sql_session_pass);
#mysql_select_db($sql_default_db);
date_default_timezone_set('America/Los_Angeles');
setcookie("test","test");
return TRUE;
}
The read function can set a cookie right up until the very moment it returns a value.
function read($session_id)
{
$time = time();
$query = "SELECT * FROM 'sessions' WHERE 'expires' > '$time'";
$query_result = mysql_query($query);
$data = '';
/* fetch the array and start sifting through it */
while($session_array = mysql_fetch_array($query_result))
{
/* strip the slashes from the session array */
$session_array = $this->strip($session_array);
/* authenticate the user and if so return the session data */
if($this->auth_check($session_array,$session_id))
{
$data = $session_array['data'];
}
}
setcookie("testcookie1","value1",time()+1000,'/');
return $data;
}
The very first line of the write function is setting another cookie and it cannot because the headers are already sent.
From the manual for session_set_save_handler():
Note: The "write" handler is not
executed until after the output stream
is closed. Thus, output from debugging
statements in the "write" handler will
never be seen in the browser. If
debugging output is necessary, it is
suggested that the debug output be
written to a file instead.
Essentially, writing changes to session data (calling the registered session write function) does not happen until PHP is almost completely done with its execution cycle. By this time, all your output has already been sent and it is not possible to modify the header information, so setcookie() won't work.
You can have it write data earlier by using session_write_close().