• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Session serialized data... kinda? Dont understand the format

#1
Im trying to keep track of what accounts have which sessions open by creating a record in a table that will associate the account_id -> session_id, to do this, im creating a My_Session_database_driver.php, with the following content so far:
PHP Code:
<?php defined('BASEPATH') OR exit('No direct script access allowed');

class 
MY_Session_database_driver extends CI_Session_database_driver {

    public function 
write($session_id$session_data)
    {
        if(
$session_data)
            
$data unserialize($session_data);

        if (
$this->_row_exists === FALSE && isset($data['account_id']))
        {
            
$this->_db->insert('account_session_assoc', [
                
'account_id' => $data['account_id'],
                
'session_id' => $session_id
            
]);
         } 
        

        return 
parent::write($session_id$session_data);
    }


The part that im running into an issue, is the session data. I thought at first it was serialized data that was base64encrypted then stored in the database

When I create a session with the session data ['account_id' => '1'], the value of $session_data handed to the write() method is:
Quote:__ci_last_regenerate|i:1440050385;account_id|s:1:"1";
To me, that doesn't look like a fully serialized string... If I serialize the above array, the result is:
Quote:a:2:{s:20:"__ci_last_regenerate";i:1440050385;s:10:"account_id";s:1:"1";}

So my question is... Why isnt it fully serialized? And how can I easily "unserialize" it, or whatever it is to get the data?

Thanks
Reply

#2
It's Base64-encoded, not encrypted - there's a big difference.
And it is "fully serialized", just not via the serialize() function.

session_decode() can be used to unserialize the data, but that function puts the result directly into $_SESSION instead of returning it, and that's a quite big issue ... you don't want that; you should look for another way to do what you're trying to do.
Just add a user_id INT DEFAULT NULL field to the session table and update it on login, don't look for a complicated solution.

Subtle but important details like these are the reason I suggested (in the other thread) that you don't try to deal with the low-level drivers' code. You don't know how a session works internally and therefore you shouldn't be messing with it.
Reply

#3
(08-20-2015, 12:55 AM)Narf Wrote: It's Base64-encoded, not encrypted - there's a big difference.
And it is "fully serialized", just not via the serialize() function.

session_decode() can be used to unserialize the data, but that function puts the result directly into $_SESSION instead of returning it, and that's a quite big issue ... you don't want that; you should look for another way to do what you're trying to do.
Just add a user_id INT DEFAULT NULL field to the session table and update it on login, don't look for a complicated solution.

Subtle but important details like these are the reason I suggested (in the other thread) that you don't try to deal with the low-level drivers' code. You don't know how a session works internally and therefore you shouldn't be messing with it.

I would MUCH rather put a single column in the ci_sessions table, I thought you were against that initially...

And if its encoded and not encrypted, then I would think base64decode would work, using the following:

PHP Code:
log_message('error','DECODED DATA: ' print_r(base64_decode($session_data), TRUE)); 

   

That doesnt work, obviously.

You dont like that im trying to get it from the session data... which I dont get. Im not messing with the data as far as CI is concerned, im just intercepting it to read it, and passing it as it is back to CI... as far as CI is concerned, it never gets changed. Im hardly even messing with the framework. I just create the MY_Session_database_driver::write method to read the params, then pass the data EXACTLY as it is given, to the CI_Session_database_driver::write method, so whats the big deal? (Ps, if any of that sounded rude, sorry, im not trying to come off that way, just dont get why you are so uptight that im doing this)
Reply

#4
(08-20-2015, 12:55 AM)Narf Wrote: It's Base64-encoded, not encrypted - there's a big difference.
And it is "fully serialized", just not via the serialize() function.

session_decode() can be used to unserialize the data, but that function puts the result directly into $_SESSION instead of returning it, and that's a quite big issue ... you don't want that; you should look for another way to do what you're trying to do.
Just add a user_id INT DEFAULT NULL field to the session table and update it on login, don't look for a complicate
PHP Code:
private function _assoc_session($account_id$session_id)
 
   {
 
       return self::$db
            
->where'id'$session_id )
 
           ->update('ci_sessions', ['account_id' => $account_id]);
 
   
d solution.

Subtle but important details like these are the reason I suggested (in the other thread) that you don't try to deal with the low-level drivers' code. You don't know how a session works internally and therefore you shouldn't be messing with it.

Alright, I just ended up doin it your way.
Reply

#5
(08-21-2015, 10:11 AM)jLinux Wrote:
(08-20-2015, 12:55 AM)Narf Wrote: It's Base64-encoded, not encrypted - there's a big difference.
And it is "fully serialized", just not via the serialize() function.

session_decode() can be used to unserialize the data, but that function puts the result directly into $_SESSION instead of returning it, and that's a quite big issue ... you don't want that; you should look for another way to do what you're trying to do.
Just add a user_id INT DEFAULT NULL field to the session table and update it on login, don't look for a complicated solution.

Subtle but important details like these are the reason I suggested (in the other thread) that you don't try to deal with the low-level drivers' code. You don't know how a session works internally and therefore you shouldn't be messing with it.

I would MUCH rather put a single column in the ci_sessions table, I thought you were against that initially...

I warned you about altering the session drivers' implementation, not about adding a column - that's not the same thing.

(08-21-2015, 10:11 AM)jLinux Wrote: And if its encoded and not encrypted, then I would think base64decode would work, using the following:


PHP Code:
log_message('error','DECODED DATA: ' print_r(base64_decode($session_data), TRUE)); 



That doesnt work, obviously.

Encoding means translating data from one format to another. The sole reason for it being base64-encoded in the first place is that serialized session data is binary (even if some serialize formats may seem human-readable) and that state must be preserved inside a non-binary database field type.
Chances are, your session.serialize_handler INI setting is set to 'php_binary', which just looks like garbage to the human eye because it doesn't use a human language. That doesn't mean it's encrypted ... encryption keeps secrets, while in this case the data isn't secret - it's all there completely unprotected, just written in another, machine language.

(08-21-2015, 10:11 AM)jLinux Wrote: You dont like that im trying to get it from the session data... which I dont get. Im not messing with the data as far as CI is concerned, im just intercepting it to read it, and passing it as it is back to CI... as far as CI is concerned, it never gets changed. Im hardly even messing with the framework. I just create the MY_Session_database_driver::write method to read the params, then pass the data EXACTLY as it is given, to the CI_Session_database_driver::write method, so whats the big deal? (Ps, if any of that sounded rude, sorry, im not trying to come off that way, just dont get why you are so uptight that im doing this)

The ability to extend the framework, especially at that level, is very carefully crafted and exists becase I personally chose to allow it - I'm not "uptight" about you messing with it.

I'm uptight because you think you know what you're doing, you have the confidence that you do, yet you really don't ... You don't know how to read the data in the first place, and you certainly don't understand that it may even be impossible to intercept it without modifying, otherwise you wouldn't say that you're only reading it.

I too may seem rude or hostile, but I'm a rational man ... if I appear that way here, it's just because I'm inclined to warn you about dangers that you're not prepared for, and in my experience people ignore warnings if they aren't strongly worded.
Reply

#6
@Narf

So I got it working so far, but running into a little error. The session client will start a new session every X minutes, I think its after the current one expires. It wont log them out, it will just pass them over to another session.

This wouldnt be an issue if the session association was done in the My_Session_database_driver class, which is kinda why I wanted to do it in the first place there, I figured something like this would come up.

So, back to my initial question... Since the base64decode doesnt seem to properly decode the session data (when its a string, just before the session is logged to the DB), how can I decode it?

Im currently just going right for the session variable, which i dont think thats the best way to do it in CI, esp if I can look right thru the session data thats already in the function.

PHP Code:
if ($this->_row_exists === FALSE && isset($_SESSION['account_id'])) 
Reply

#7
i was trying to make a useronline function , bt while i tried unserialize($row->data), it through an error.... what should i do noow???
Reply

#8
jLinux, the session ID is regenerated in sess_regenerate() ... you can safely extend that method and update the new table row.
Reply

#9
(08-21-2015, 01:15 PM)Narf Wrote: I'm not "uptight"

Alright, just seemed like it...

(08-21-2015, 01:15 PM)Narf Wrote: I'm uptight because you think you know what you're doing, you have the confidence that you do, yet you really don't ... You don't know how to read the data in the first place,
I know what my end goal was, my issue was reading the session data, Im not sure what gave you the impression that i was mr confident when working with CI, if I was, I dont think id be asking the question in the first place. Im a Linux Engineer, not a PHP developer, Im just working on a PHP project right now.

As far as reading the data, I asked you a few times, I mistakingly said "base64encrypted" once, when I meant encoded, and told you that base64decoding didnt work, which you still haven't explained that. I apologize that I dont know PHP inside and out, I dont code all day every day, if you do, then good for you.

(08-21-2015, 01:15 PM)Narf Wrote: and you certainly don't understand that it may even be impossible to intercept it without modifying, otherwise you wouldn't say that you're only reading it.

Apparently I don't get it.... explain how this is modifying $session_data, or how it would hinder CI
PHP Code:
class MY_Session_database_driver extends CI_Session_database_driver {

 public function 
write($session_id$session_data)
 {
 
$my_session_data $session_data;

 
// Do something with $my_session_data 

 
return parent::write($session_id$session_data);
 }

(08-22-2015, 02:21 AM)Narf Wrote: jLinux, the session ID is regenerated in sess_regenerate() ... you can safely extend that method and update the new table row.
Thanks! 
Reply

#10
The code to associate the session data is in the summarized code below:
PHP Code:
class MY_Session_database_driver extends CI_Session_database_driver {

    public function 
write($session_id$session_data)
    {
        
// If theres an account ID set in the session data...
        
if (isset($_SESSION['account_id']))
        {
            
// ... Associate the account ID to the session ID
            
Accounts_model::assoc_session($_SESSION['account_id'], $session_id);
         }        

        return 
parent::write($session_id$session_data);
    }


PHP Code:
class MY_Session extends CI_Session
{
 
   public function sess_regenerate($destroy FALSE)
 
   {
 
       $current_session session_id();

 
       parent::sess_regenerate($destroy);

 
       $new_session session_id();

 
       // Re-associate all old account activity to the new session
 
       Accounts_model::assoc_session(NULL$current_session$new_session);
 
   }


Which works fine when the session is being created initially, but it looks like when the sess_time_to_update is reached, it throws an error:
Quote:PHP Fatal error:  Class 'Accounts_model' not found in /Users/me/PhpstormProjects/project-App/htdocs/application/libraries/Session/drivers/MY_Session_database_driver.php on line 12

So the Accounts model isnt getting loaded before the session is being regenerated. Its probably not best to try and load it before is it? What would you suggest in this case?

My goal is to have the sessions associated to the accounts, which is working fine, and when the session is regenerated, move the account activity data (NOT THe session data, totally different table) that is associated to the old session ID, to the new session ID. Thus when viewing all the activity for a user, they can see everything that happened for the users activity in one list, as opposed to multiple lists under different sessions
Reply


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.