13 Replies - 2065 Views - Last Post: 09 January 2012 - 11:39 PM Rate Topic: -----

#1 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

New to session_set_save_handler

Posted 13 December 2011 - 05:57 PM

I"m getting ready to use session_set_save_handler and I'll probably need some help.

Never used it before so I'm going to mess up probably.

I'll post some code as I go so I can get some feedback.

A few questions to start with before I begin.
1. If I don't like classes is that ok?(Most custom session tutorials I found use classes. I prefer first class objects so I'm not really keen on using classes. Just my opinion. Not that I couldn't do it. Functional programming is my fun and that works well with first class objects. That said, I hope the creators of php implement them in cooler ways in the future.)
2. Is there a way to make a general custom session handler that will just accept parameters and use that to create a session of any size of variables?
3. Can sessions be made to use an array that's unserialized from a database.
4. When using sessions as arrays should the array be serialized before its placed in the session or should the custom session handler do that?
5. Would it be extreme to use runkit_function_add(), runkit_function_redefine(), runkit_function_copy(), runkit_function_rename(), runkit_function_remove() to dynamically create functions that can be used to create new custom session handlers that can be used to make any sort of session.
6. Can lambdas and anonymous functions call or generate session variables.(I just haven't tried yet.)
7. Can a function factory be created using lambdas and anonymous functions or maybe use the stuff from question 5 to do that with lambdas.

I think that's it for now.
I'm hoping to abstract away the session interface so it's easier to use. Abstraction without classes is a not as easy, but I'd like to try. Just gonna use functions.

I'm mostly a hobby programmer right now so you won't have to worry about me cheating at school.(I don't go. Web searches, books from the book store, and forums like this are my school right now.)

I mostly learn by copying letter by letter(looking at a tutorial and just writing it out), but I'm having trouble finding information about the specific topics of db sessions and most of the other topics in my questions. I'm pretty good at functional programming so I'd like to use that method to handle php sessions. There is hardly much for reference on the topic of using lambdas with sessions.

Aside the lack of knowledge about the topics at hand I've noticed that each time I find a new element in a language the more complex the mechanism is the more likely there will be unpublished parts of the theory.
I understand there are limits to what can be published because of time and complexity, and that's why I'm here asking questions about this. I'll be coding this stuff whether or not some one helps me. If there are any very knowledgeable people on these subjects I could use some help so my head doesn't explode with testing code while I also learn it.

I might split this topic into other topics if my questions become more specific.

P.S. Don't point me to a link like the PHP docs or some other tutorial. Hell, even if it's not the PHP docs I've probably been there. I search google like I'm a horse and google is my grazing field. If you're too busy to answer every thing or most of it feel free to answer just a few things if you can. Time is precious.

This post has been edited by hiddenghost: 13 December 2011 - 07:03 PM


Is This A Good Question/Topic? 0
  • +

Replies To: New to session_set_save_handler

#2 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 13 December 2011 - 06:53 PM

I just thought of some questions.

Is setting up a session_set_save_handler for sql just a matter of making queries inside the callback functions?

If that's so can I just treat the session kind of like a regular sql query where the events in the sql kind of match what the callback type is.

Kind of like:

"close" inside the callback of session_set_save_handler would be equal to:
mysqli_close($link);
or "read" would be a equal to:
"SELECT row1, row2, ...
FROM a_table"

But if that's so how can I use session globals, or are those even needed when using a database? How does the interface for sessions work once a custom handler is in place?

That's the disconnect for me.
How do the names get used? Is it like $SESSION['a_thing']? If so how can I make sure that the database query uses the $SESSION array? Is it automatic or what?

I've been using mysqli_fetch_array for regular queries. What's the analog to that when using a custom session handler? Is the array automatically generated inside session_set_save_handler?

This post has been edited by hiddenghost: 13 December 2011 - 06:57 PM

Was This Post Helpful? 0
  • +
  • -

#3 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 13 December 2011 - 07:35 PM

Ok. After some looking at the PHP docs I think there may be a way.

The session_set_save_handler arguments for callback all have similar one shot functions like session_unset and session_write_close and session_destroy. I could place these in a function. The only issue with that is that I don't know if a db query will work with session_save_path.

And then from there how can I read it as a session?

Just talking to myself here. :smile2:
Was This Post Helpful? 0
  • +
  • -

#4 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 13 December 2011 - 07:50 PM

Crap. I just realized.

The PHP docs say:
Caution

If you are using $_SESSION (or $HTTP_SESSION_VARS), do not use session_register(), session_is_registered(), and session_unregister().

So can the $_SESSION array automatically update a db when using session_set_save_handler?
Was This Post Helpful? 0
  • +
  • -

#5 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3394
  • View blog
  • Posts: 9,592
  • Joined: 08-June 10

Re: New to session_set_save_handler

Posted 14 December 2011 - 04:26 AM

View Posthiddenghost, on 14 December 2011 - 03:50 AM, said:

So can the $_SESSION array automatically update a db when using session_set_save_handler?

it automatically updates if
- the script ends
- you call session_write_close()

what session_set_save_handler() does is defining how PHP reads/writes to the session storage device.
Was This Post Helpful? 3
  • +
  • -

#6 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 14 December 2011 - 09:47 AM

Ah. Thank you very much Dormilich.

Does that work with the 'close' parameter in session_set_save_handler?
Or is session_write_close initiating the 'close' parameter in session_set_save_handler?
Was This Post Helpful? 0
  • +
  • -

#7 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3394
  • View blog
  • Posts: 9,592
  • Joined: 08-June 10

Re: New to session_set_save_handler

Posted 14 December 2011 - 10:17 AM

session_write_close() initiates the close and write actions of any session handler. session_set_save_handler() only overwrites the native implementations with your own.
Was This Post Helpful? 1
  • +
  • -

#8 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 29 December 2011 - 05:02 PM

View PostDormilich, on 14 December 2011 - 11:17 AM, said:

session_write_close() initiates the close and write actions of any session handler. session_set_save_handler() only overwrites the native implementations with your own.


I got busy on something else for a while. Now I'm coming back to this thread instead of a new one.

Ok. Is there not a specific way to write the new session handlers.

Can I just treat them like regular queries but they get called by the session_set_save_handler() function.

This is where I get confused a lot. If the session_set_save_handler is initiating the queries what context do the queries belong in with respect to regular queries.

Oh well. I guess I can just start writing something and watch it fail. I can work out the code from there.
Was This Post Helpful? 0
  • +
  • -

#9 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3394
  • View blog
  • Posts: 9,592
  • Joined: 08-June 10

Re: New to session_set_save_handler

Posted 29 December 2011 - 07:45 PM

session_set_save_handler() does not initiate any queries. it just tells PHP what to do, if a session action (open/close/read/write/destroy/GC) e.g. triggered through a session function (session_start() would certainly call the open-handler) is invoked.


you may check this code of an example implementation
<?php
/*
 * Copyright (c) 2009-2011 Bertold von Dormilich <Dormilich at netscape dot net>
 *      
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

class SessionManager
{
	/**
	 * @var (int) $lifeTime            session lifetime in seconds
	 * @var (PDOStatement) $_read      PDO read statement
	 * @var (PDOStatement) $_write     PDO write statement
	 * @var (PDOStatement) $_destroy   PDO delete statement
	 * @var (PDOStatement) $_gc        PDO Garbage Collector statement
	 */
	private
		  $lifeTime
		, $_read 
		, $_write
		, $_destroy
		, $_gc
	;
	
	/**
	 * initialize the session handling functions and start the session.
	 *
	 * @param (PDO) $PDO               database connection object
	 * @return (void)
	 */
	public function __construct(
		PDO $PDO
	)
	{
		try
		{
			$this->setHandlers($PDO);
	
			session_set_save_handler(
				  array($this, 'open')
				, array($this, 'close')
				, array($this, 'read')
				, array($this, 'write')
				, array($this, 'destroy')
				, array($this, 'gc')
			);
		}
		catch (Exception $e)
		{
			Logger::add($e, __METHOD__);
		}
	}
	
	/**
	 * set the PDOStatement objects responsible for read/write/destroy/gc.
	 *
	 * @param (PDO) $PDO               database connection object
	 * @return (void)
	 */
	private function setHandlers(
		PDO $PDO
	)
	{
		$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
		$sql_read = "SELECT session_data FROM sessions WHERE session_id = :sid AND expires > NOW();";
		$this->_read = $PDO->prepare($sql_read);
		
		$sql_write = "SELECT write_session_data(:sid, :data, :time);";
		$this->_write = $PDO->prepare($sql_write);
		
		$sql_destroy = "DELETE FROM sessions WHERE session_id = :sid;";
		$this->_destroy = $PDO->prepare($sql_destroy);
		
		$sql_gc = "DELETE FROM sessions WHERE expires < NOW();";
		$this->_gc = $PDO->prepare($sql_gc);
	}			
	
	/**
	 * code to execute when a session is opened (constructor).
	 * the DB connection has already been taken care of in the constructor.
	 * the session handling functions are actually defined through an 
	 * interface, therefore the parameters do not always make sense.
	 *
	 * @param (string) $save_path      session save directory
	 * @param (string) $session_name   session name
	 * @return (bool)
	 */
	public function open(
		  $save_path
		, $session_name
	)
	{
		return true;
	}
	
	/**
	 * code to execute, when a session is closed (destructor). PDO is closed
	 * automatically on destruction of the appropriate PDO object [1].
	 *
	 * @return (bool)
	 */
	public function close()
	{
		return true;
	}
	
	/**
	 * get (all) session data from the storage device.
	 *
	 * @param (string) $id             session id
	 * @return (string)                (serialized) session data
	 */
	public function read(
		$id
	)
	{
		try
		{
			$params = array('sid' => $id);
			$this->_read->execute($params);
			$data = $this->_read->fetchColumn(0);
		}
		catch (Exception $e)
		{
			Logger::add($e, __METHOD__);
			return '';
		}
		return (is_string($data)) ? $data : '';
	}
	
	/**
	 * write (all) session data to the storage device.
	 *
	 * @param (string) $id             session id
	 * @param (string) $data           (serialized) session data 
	 *                                 (serialization is done by PHP)
	 * @return (bool)
	 */
	public function write(
		  $id
		, $data
	)
	{
		try 
		{
			$params = array(
				  'sid'  => $id
				, 'data' => $data
				, 'time' => $this->expiryDate()
			);
			$this->_write->execute($params);
		} 
		catch (Exception $e) 
		{
			Logger::add($e, __METHOD__);
		}
		return true; 
	}
	
	/**
	 * delete session data from storage device. this function is called, when
	 * a session is ended by session_destroy().
	 *
	 * @param (string) $id             session id
	 * @return (bool)
	 */
	public function destroy(
		$id
	)
	{
		try
		{
			$params = array('sid' => $id);
			$this->_destroy->execute($params);
		} 
		catch (Exception $e) 
		{
			Logger::add($e, __METHOD__);
		}
		return true;
	}
	
	/**
	 * garbage collector function. with a set probability PHP will run
	 * the garbage collector to delete expired session data.
	 *
	 * @return (bool)
	 */
	public function gc()
	{
		try
		{
			$this->_destroy->execute();
		} 
		catch (Exception $e) 
		{
			Logger::add($e, __METHOD__);
		}
		return true;
	}
	
	/**
	 * SQL TIMESTAMP compatible datetime string of the new expiry time.
	 *
	 * @return (string)                timestamp string
	 */
	private function expiryDate()
	{
		return date(
			"Y-m-d H:i:s", 
			$_SERVER['REQUEST_TIME'] + ini_get('session.gc_maxlifetime')
		);
	}
}
/*
[1] - when a PDOStatement object is created, the creating PDO object is
      passed to the (internal) constructor.
 */

This post has been edited by Dormilich: 29 December 2011 - 07:46 PM

Was This Post Helpful? 3
  • +
  • -

#10 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 06 January 2012 - 09:02 PM

View PostDormilich, on 29 December 2011 - 08:45 PM, said:

session_set_save_handler() does not initiate any queries. it just tells PHP what to do, if a session action (open/close/read/write/destroy/GC) e.g. triggered through a session function (session_start() would certainly call the open-handler) is invoked.


Ok, I think I'm getting it now.

The session functions use the session_set_save_handler() while the functions I call with the handler do the work.
I could put in my own file writes if I wanted to go through all the work.

I'm not familiar with PDO so it's a little hard for me to see how exactly that class is using a database to perform inserts.

On the php tutorial site it reads that PDO requires drivers that I'm not currently using. I've just been doing regular queries. :)

I see it can be used for object query mapping. I'm resisting using that because I'm also resisting class oop in code right now. Just a preference while I'm working on my project. The only syntax for class oop I really like is in Python, and I still prefer lambdas.

I suppose that brings me to my next two questions.
If I'm just using procedural functions where do I put the db link and quarry in php for the session handler?
Is this next statement right?
In the case where I'd being using mysql I'd have specific columns according to what session data I want to store in my tables to accept the user session data and the queries in the functions used by session_set_save_handler would have inserts,deletes,or updates that would use those columns when writing, deleting, and so on.

This post has been edited by hiddenghost: 06 January 2012 - 09:03 PM

Was This Post Helpful? 0
  • +
  • -

#11 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3394
  • View blog
  • Posts: 9,592
  • Joined: 08-June 10

Re: New to session_set_save_handler

Posted 07 January 2012 - 07:08 AM

View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

The session functions use the session_set_save_handler() while the functions I call with the handler do the work.

not exactly. the session functions use those functions, that are assigned to the session actions (read, write, etc.). in the default state, there are functions already registered by PHP (file read/write). session_set_save_handler() has the only purpose to change these assignments to user provided functions. after you assigned new functions, session_set_save_handler() is not used any more.


View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

I could put in my own file writes if I wanted to go through all the work.

yes.


View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

I'm not familiar with PDO so it's a little hard for me to see how exactly that class is using a database to perform inserts.

the class is using an already existing connection (the PDO object passed in the constructor). this is called Dependency Injection.



View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

On the php tutorial site it reads that PDO requires drivers that I'm not currently using. I've just been doing regular queries. :)

if you install PDO, the drivers are installed alongside (PDO does not work without drivers). besides that, drivers are not queries. the driver is used by PDO to communicate with a database (e.g. a MySQL, PostgreSQL, SQLite or DB2 database). for procedural programming that would correspond to the function prefix, you have mysql_query() (MySQL), pgsql_query() (PostgreSQL), sqlite_query() (SQLite), etc. PDO uses a DSN to communicate with the DB and then only its PDO->query() method (that way changing from MySQL to PostgreSQL only* requires you to change the DSN, not all of your code)

* - given that the used SQL statements are supported by both DBs


View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

If I'm just using procedural functions where do I put the db link and quarry in php for the session handler?

the query just goes into the function that you assign.
// this DOES NOT work (see explanation)
function session_read($id)
{
    $res  = mysql_query("SELECT session_data FROM sessions WHERE session_id = $id AND expires > NOW()", $conn);
    $data = mysql_fetch_row();
    return $data[0];
}

as far as queries go, that’s easy. the problem comes with the connection (DB link). you can’t pass it as argument (the arguments are defined/constrained by PHP) and you can’t use globals (bad practice and maybe some call stack issues). that is why I used OOP, where I can save the DB link inside the query object (or rather PDO does that automatically). you can’t omit the DB link either because mysql_query() would use the last active link, which is not necessarily the one to your session DB. you could of course open and close the connection on each access, but that is bad practice either.


View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

Is this next statement right?
In the case where I'd being using mysql I'd have specific columns according to what session data I want to store in my tables to accept the user session data and the queries in the functions used by session_set_save_handler would have inserts,deletes,or updates that would use those columns when writing, deleting, and so on.

no.

the session DB would only have one column for session data. $_SESSION (where you get your data from) is an array, which is serialized when writing to the storage device (cf. session.serialize_handler) and vice versa.

This post has been edited by Dormilich: 09 January 2012 - 11:25 PM
Reason for edit:: changed link to the english version

Was This Post Helpful? 1
  • +
  • -

#12 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 09 January 2012 - 09:36 PM

Der Link, den Sie mir gab, war in Deutsch?

View PostDormilich, on 07 January 2012 - 08:08 AM, said:

View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

I'm not familiar with PDO so it's a little hard for me to see how exactly that class is using a database to perform inserts.

the class is using an already existing connection (the PDO object passed in the constructor). this is called Dependency Injection.


I'm still learning about oop patterns. I might have to start another thread about that in the future.

View PostDormilich, on 07 January 2012 - 08:08 AM, said:

View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

If I'm just using procedural functions where do I put the db link and quarry in php for the session handler?

the query just goes into the function that you assign.
// this DOES NOT work (see explanation)
function session_read($id)
{
    $res  = mysql_query("SELECT session_data FROM sessions WHERE session_id = $id AND expires > NOW()", $conn);
    $data = mysql_fetch_row();
    return $data[0];
}

as far as queries go, that’s easy. the problem comes with the connection (DB link). you can’t pass it as argument (the arguments are defined/constrained by PHP) and you can’t use globals (bad practice and maybe some call stack issues). that is why I used OOP, where I can save the DB link inside the query object (or rather PDO does that automatically). you can’t omit the DB link either because mysql_query() would use the last active link, which is not necessarily the one to your session DB. you could of course open and close the connection on each access, but that is bad practice either.


View Posthiddenghost, on 07 January 2012 - 05:02 AM, said:

Is this next statement right?
In the case where I'd being using mysql I'd have specific columns according to what session data I want to store in my tables to accept the user session data and the queries in the functions used by session_set_save_handler would have inserts,deletes,or updates that would use those columns when writing, deleting, and so on.

no.

the session DB would only have one column for session data. $_SESSION (where you get your data from) is an array, which is serialized when writing to the storage device (cf. session.serialize_handler) and vice versa.


Thank you so much!

All these answers in this thread cover almost all the questions I'd ever need answered for this particular topic.

I did think of another question.

Do I need to set the custom session handler on every page/script that uses it, or just after the session is closed?
It's more of a question of timing. If the session is active does the custom handler need to be used on every page, or are the settings persitant until the session closes?
The session variables are global, but I was wondering how they behave with a custom setting as far as when the setting is effective.

This post has been edited by hiddenghost: 09 January 2012 - 09:47 PM

Was This Post Helpful? 0
  • +
  • -

#13 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 39
  • View blog
  • Posts: 621
  • Joined: 15-December 09

Re: New to session_set_save_handler

Posted 09 January 2012 - 09:52 PM

View PostDormilich, on 07 January 2012 - 08:08 AM, said:

as far as queries go, thatís easy. the problem comes with the connection (DB link). you canít pass it as argument (the arguments are defined/constrained by PHP) and you canít use globals (bad practice and maybe some call stack issues). that is why I used OOP, where I can save the DB link inside the query object (or rather PDO does that automatically). you canít omit the DB link either because mysql_query() would use the last active link, which is not necessarily the one to your session DB. you could of course open and close the connection on each access, but that is bad practice either.


Why is that bad practice?
Was This Post Helpful? 0
  • +
  • -

#14 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3394
  • View blog
  • Posts: 9,592
  • Joined: 08-June 10

Re: New to session_set_save_handler

Posted 09 January 2012 - 11:39 PM

View Posthiddenghost, on 10 January 2012 - 05:36 AM, said:

Der Link, den Sie mir gab, war in Deutsch?

oops. corrected.


View Posthiddenghost, on 10 January 2012 - 05:36 AM, said:

Do I need to set the custom session handler on every page/script that uses it, or just after the session is closed?
It's more of a question of timing. If the session is active does the custom handler need to be used on every page, or are the settings persitant until the session closes?
The session variables are global, but I was wondering how they behave with a custom setting as far as when the setting is effective.

1) you need to set it on every script (though only once per request)

2) a session is not active in the sense of a running process. it is just a bunch of data ready to be used. what makes a session active is just the ID of the session (and a timeout, which is usually a timestamp (e.g. a file's mtime, a DB DATE column, etc.)). hence you need to invoke the session handler for every request.

3) session variables are only global in the sense that $_SESSION is a superglobal. a custom session handler does not change that, only how PHP stores the session data.


View Posthiddenghost, on 10 January 2012 - 05:52 AM, said:

View PostDormilich, on 07 January 2012 - 08:08 AM, said:

[...] you could of course open and close the connection on each access, but that is bad practice either.


Why is that bad practice?

because you create unnecessary connections/waste of resources. all you need is to open the connection on script start and close it on script end.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1