Storing Database Connection in a Session Variable

Storing database connection in a session variable

Even if you could do this (resource vs. data), this is a bad idea. You'll wind up with lots of concurrent open connections, which will blow your max connections very quickly... especially if its lifecycle is expanded beyond sub 100ms (depending on your queries) to 20 minutes or more. With open connections, something like MySQL also won't be able to reset its memory allocations properly, and the whole system sort of goes to hell. In short, this is not what DBs are for unless the only consumer of your code will be a single user.

As an alternative, I'd highly recommend caching technologies which are designed specifically to reduce database load and obviate connection times. Using something like, at its simplest, memcached will dramatically improve performance all the way around, and you'll be able to specify exactly how many system resources go into the cache -- while letting the database do its job of getting data when it needs to.

What to put in a session variable

This is pretty hard to answer because it's so application-specific, but here are a few guidelines I use:

  1. Put as little as possible in the session.
  2. User-specific selections that should only last during a given visit are a good choice
  3. often, variables that need to be accessible to multiple pages throughout the user's visit to your site (to avoid passing them from page to page) are also good to put in the session.

From what little you've said about your application, I'd probably select your data from the db and try to find ways to minimize the impact of those queries instead of loading down the session.

Avoid storing connection string in session for different sql schema

There is no security harm to store connection string in session, as session values are not stored in Cookie. Only Session ID will be stored in cookie, and each values of session stored in server along with the Session ID.

But the connection string is common for group of users who access the application, in your case tenant. So storing in session will use more memory. Always try to use Context Approach, for example your Data Layer code will refer connection string as follows

String con=AppContext.Current.ConnectionString;

Above AppContext class will have actual logic to retrieve the connection string based on type of the host, such as worker role, web role, unit test etc..

•You can store the connection string in web.config, and key can be prefixed with sub domain value
Example: Subdomain1_connection =connection string

•You can store them in a data base if you have central DB where all the tenants information stored

•If you don’t have such DB, you can create Azure table to store tenant information

I always have two context variables in any multi-tenant application, AppContext and UserContext, this two contexts provides appropriate data. So my unit test don’t bother about sessions, the context will deliver the values from static dictionary OR session OR database OR Azure table based on where my app is running.

Cannot store database connection inside the $_SESSION

Anything that is stored inside a session needs to be serializable. Why do you want to store the connection inside a session at all? This does not make sense to me. Just reconnect with every request.

How do I save PHP session data to a database instead of in the file system?

I have found over the course of several hours debugging that the referenced articles found on numerous Google searches as well as a significant subset of Stack Overflow answers such as here, here and here all provide invalid or outdated information.

Things that can cause [critical] issues with saving session data to a database:

  • While all the examples online state that you can "fill" the session_set_save_handler, none of them state that you must also set the register_shutdown_function('session_write_close') too (reference).

  • Several (older) guides refer to an outdated SQL Database structure, and should not be used. The database structure that you need for saving session data to the database is: id/access/data. That's it. no need for various extra timestamp columns as I've seen on a few "guides" and examples.

    • Several of the older guides also have outdated MySQL syntax such as DELETE * FROM ...
  • The class [made in my question] must implement the SessionHandlerInterface . I have seen guides (referenced above) that give the implementation of sessionHandler which is not a suitable interface. Perhaps previous versions of PHP had a slightly different method (probably <5.4).

  • The session class methods must return the values set out by the PHP manual. Again, probably inherited from pre-5.4 PHP but two guides I read stated that class->open returns the row to be read, whereas the PHP manual states that it needs to return true or false only.

  • This is the cause of my Original Issue: I was using custom session names (actually id's as session names and session id's are the same thing!) as per this very good StackOverflow post and this was generating a session name that was 128 characters long. As the session name is the sole key that is needed to be cracked to compromise a session and take over with a session hijacking then a longer name/id is a very good thing.

    • But, this caused an issue because MySQL was silently slicing the session id down to just 32 characters instead of 128, so it was never able to find the session data in the database. This was a completely silent issue (maybe due to my database connection class not throwing warnings of such things). But this is the one to watch out for. If you have any issues with retrieving sessions from a database first check is that the full session id can be stored in the field provided.

So with all that out of the way there are some extra details to add as well:

The PHP manual page (linked above) shows an unsuitable pile of lines for a class object:

$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();

Whereas it works just as well if you put this in the class constructor:

class MySessionHandler implements SessionHandlerInterface {

private $database = null;

public function __construct(){

$this->database = new Database(whatever);

// Set handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
register_shutdown_function('session_write_close');
session_start();
}
...
}

This means that to then start a session on your output page all you need is:

<?php
require "path/to/sessionhandler.class.php";
new MySessionHandler();

//Bang session has been setup and started and works

For reference the complete Session communication class is as follows, this works with PHP 5.6 (and probably 7 but not tested on 7 yet)

<?php
/***
* Created by PhpStorm.
***/
class MySessionHandler implements SessionHandlerInterface {
private $database = null;

public function __construct($sessionDBconnectionUrl){
/***
* Just setting up my own database connection. Use yours as you need.
***/

require_once "class.database.include.php";
$this->database = new DatabaseObject($sessionDBconnectionUrl);

// Set handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
register_shutdown_function('session_write_close');
session_start();
}

/**
* Open
*/
public function open($savepath, $id){
// If successful
$this->database->getSelect("SELECT `data` FROM sessions WHERE id = ? LIMIT 1",$id,TRUE);
if($this->database->selectRowsFoundCounter() == 1){
// Return True
return true;
}
// Return False
return false;
}
/**
* Read
*/
public function read($id)
{
// Set query
$readRow = $this->database->getSelect('SELECT `data` FROM sessions WHERE id = ? LIMIT 1', $id,TRUE);
if ($this->database->selectRowsFoundCounter() > 0) {
return $readRow['data'];
} else {
return '';
}
}

/**
* Write
*/
public function write($id, $data)
{
// Create time stamp
$access = time();

// Set query
$dataReplace[0] = $id;
$dataReplace[1] = $access;
$dataReplace[2] = $data;
if ($this->database->noReturnQuery('REPLACE INTO sessions(id,access,`data`) VALUES (?, ?, ?)', $dataReplace)) {
return true;
} else {
return false;
}
}

/**
* Destroy
*/
public function destroy($id)
{
// Set query
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE id = ? LIMIT 1', $id)) {
return true;
} else {

return false;
}
}
/**
* Close
*/
public function close(){
// Close the database connection
if($this->database->dbiLink->close){
// Return True
return true;
}
// Return False
return false;
}

/**
* Garbage Collection
*/
public function gc($max)
{
// Calculate what is to be deemed old
$old = time() - $max;

if ($this->database->noReturnQuery('DELETE FROM sessions WHERE access < ?', $old)) {
return true;
} else {
return false;
}
}

public function __destruct()
{
$this->close();
}

}

Usage: As shown just above the class code text.

Storing user variables in database vs session in asp.net

Interesting question. If it's data that's not important across sessions (say, last page viewed) -> session. If it's data that should be persistent (say, password) -> database. The interesting case and the one you probably refer to: Data that should be persistent but is also used often (say, the username). From these, I tend to copy those values from the DB into the session that allow me to work without database access in pages with trivial tasks.

session variables vs database

You could get the information from the database when they first log in, and then keep it in session variables until they log out or the session times out. Keeping lots of user data in session variables could create some overhead if there are many users logged in at the same time, but it will be different from making constant queries.

The best way to answer might be to ask how much other data exists for users and how much of it is likely to be needed in a "typical" session. The data that most users will require to be loaded at some point during a session could be loaded at login. Data that most users do not need during a typical session could be loaded on demand.



Related Topics



Leave a reply



Submit