I want to implement a PHP custom session ID, while avoiding calling session_start() more than necessary.
Basically, one simple algorithm is
session_start();
if ( ! isset( $_SESSION['MyStuff'] )) {
session_write_close();
session_id( generate_my_id() );
session_start();
}
$_SESSION['MyStuff'] = some stuff...;
In case the session expired or didn't exist in the first place, the first session_start() will create its own ID and send a cookie to the browser. Then the session is ended, and another one is created, with another cookie sending (plus the overhead of creating and closing a session file).
Another solution would be to test if a PHPSESSID cookie exists, and its value having the format according to the - home cooked - generate_my_id() function - then test again if the $_SESSION value. But if the session expired (no $_SESSION['MyStuff']), again, a non-necessary session_start() will have been called.
So the question is, based on my observations, actually two questions
is there a way to specify how PHP should create the session ID (doesn't seem to be possible), before calling session_start()?
is there a way to check if session_start() will have to create a new session, or will just use the one available server side? (that would eliminate its first call)
Any good alternative is welcome.
Edit
Clarification about what is a custom id.
The session ID is the string key used by PHP to retrieve a session on the server, each user having a different key. That key is usually stored in a cookie, then the browser sends that cookie with its requests to the server / PHP to "connect" to the session.
PHP sets the session ID key automatically, based on MD5(user-and-time-related-data) or SHA1(same-related-data), based on settings. Thus, the session ID is either a MD5 or a SHA1 key - hopefully unique.
A custom ID is a key created manually by the programmer (me), bypassing the md5/sha1 creation.
Yes, from 5.3 onwards you can specify the hash algorithm with session.hash_function when a session id gets generated; using your own hash algorithm is not recommended, especially since the ones that come with hash are extensively tested for spread, speed, collisions, etc.
Since cookies are typically used to perpetuate sessions, you can use that information to determine whether session_start() will create a new session or not.
The following illustrates a way to minimize the number of session_start() statements you need; it's deduced from existing code (which is OO):
do {
// discover session by cookie
if (isset($_COOKIE[session_name()])) {
session_start();
// validate session contents
if (!isset($_SESSION['MyStuff'])) {
// destroy session and regenerate id
session_destroy();
session_regenerate_id(true); // skip this if you generate your own
} else {
// validation passed, no need to populate
break;
}
}
// populate new session
// you can use session_id($your_id) here
session_start();
$_SESSION['MyStuff'] = 'foobar';
} while (false);
The strange do { } while loop is just a glorified goto so that you can skip the second session_start() if the current session is valid.
Late answer but check the changelog for PHP v5.5.1
It refers a new interface called SessionIdInterface which only method is create_sid, although it's still undocumented.
interface SessionIdInterface {
public function create_sid ();
}
Related
I have read this code on the php wiki but I am not convinced it is actually adding protection
Login code fragment: Code that adds session ID as validation key.
session_destory();
session_regenerate_id();
$_SESSION['valid_id'] = session_id();
This validation part below is what I am not sure about:
Validation code: Code other than login. Check if session is properly initilized.
if ($_SESSION['valid_id'] !== session_id()) {
die('Invalid use of session ID');
}
Because session_id() returns the session_id of the current session, why would session_id() not be identically equal to $_SESSION['valid_id'] for a given logged in session?
Can someone explain if the above code is effective?
Thanks
By default, PHP's file-based session handler uses the session ID as part of the filename that the session data is stored in. Storing the ID inside the session data itself would be somewhat redundant.
At best the code snippet would simply verify that the session was properly initialized by your own code, and isn't just some random session that got attached somehow to this user. But ANY key/value pair you store in the session could be used for that - it doesn't have to be the session ID at all. e.g. checking for this:
$_SESSION['everything is ok'] = "Yay, it's working"
would be just as good.
Just wondering how to check if a PHP session exists... My understanding is that no matter what, if I am using sessions, I have to start my files with session_start() to even access the session, even if I know it already exists.
I've read to user session_id() to find out if a session exists, but since I have to use session_start() before calling session_id(), and session_start() will create a new ID if there isn't a session, how can I possible check if a session exists?
In PHP versions prior to 5.4, you can just the session_id() function:
$has_session = session_id() !== '';
In PHP version 5.4+, you can use session_status():
$has_session = session_status() == PHP_SESSION_ACTIVE;
isset($_SESSION)
That should be it. If you wanna check if a single session variable exists, use if(isset($_SESSION['variablename'])).
I find it best many times (depends on the nature of the application) to simply test to see if a session cookie is set in the client:
<?php
if (isset($_COOKIE["PHPSESSID"])) {
echo "active";
} else {
echo "don't see one";
}
?>
Of course, replace the default session name "PHPSESSID" with any custom one you are using.
In PHP there is something called the session name. The name is co-related to the cookie that will be being set if the session was already started.
So you can check the $_COOKIE array if there is a session cookie available. Cookies are normally the preferred form to interchange the session id for the session name with the browser.
If a cookie already exists this means that a PHP session was started earlier. If not, then session_start() will create a new session id and session.
A second way to check for that is to check the outgoing headers if the cookie for the session is set there. It will be set if it's a new session. Or if the session id changed.
isset($_SESSION) isn't sufficient because if a session has been created and destroyed (with session_destroy()) in the same execution, isset($_SESSION) will return true. And this situation may happen without your knowing about it when a 3rd party code is used. session_id() correctly returns an empty string, though, and can be called prior to session_start().
Check if session exists before calling session_start()
if(!isset($_SESSION))session_start();
You can call session_id before session_start. http://www.php.net/manual/en/function.session-id.php - read the id param
I've always simply used
if (#session_id() == "") #session_start();
Hasn't failed me yet.
Been quite a long time using this.
NOTE: # simply suppresses warnings.
Store the session_id in $_SESSION and check against it.
First time
session_start();
$_SESSION['id'] = session_id();
Starts a session and stores the randomly given session id.
Next time
session_start();
$valid_session = isset($_SESSION['id']) ? $_SESSION['id'] === session_id() : FALSE;
if (!$valid_session) {
header('Location: login.php');
exit();
}
Starts a session, checks if the current session id and the stored session id are identical (with the ternary ? as replacement for the non-existing short circuit AND in php). If not, asks for login again.
switch off the error reporting if noting is working in your php version put top on your php code
error_reporting(0);
I solved this three years ago, but I inadvertently erased the file from my computer.
it went like this. 3 pages that the user had to visit in the order I wanted.
1) top of each php page
enter code heresession start();enter code here
2) first page:
a) enter code here$_session["timepage1"] = a php date function; time() simple to use
b) enter code here$_session["timepage2"]= $_session["timepage1"];
b) enter code here$_session["timepage3"]=$_session["timepage1"];
3) second page:
a) enter code here$_session["timepage2"] = a php date function; time() simple to use
b) enter code here$_session["timepage3"]= $_session["timepage3"];
3) third page:
a) enter code here$_session["timepage3"] = a php date function; time() simple to use
the logic:
if timepage3 less than timepage3 on page 2
{the user has gone to page 3 before page 2 do something}
if timepage2 on page 2 less than timepage1
{the user may be trying to hack page two we want them on page 1 do something}
timepage1 should never equal timepage2 or timepage3 on any page except page1 because if it is not greater on pages two or three the user may be trying to hack "do something"
you can do complex things with simple arithmetic with the 3 timepage1-2-3 variables. you can either redirect or send a message to say please go to page 2. you can also tell if user skipped page 2. then send back to page 2 or page one, but best security feature is say nothing just redirect back to page1.
if you enter code hereecho time(); on every page, during testing, you will see the last 3 digits going up if you visit in the correct order.
I have a situation where I've started a session with:
session_id( $consistent_session_name_for_user );
session_start();
$_SESSION['key'] = $value;
but then later I decide I don't actually want to "commit" (write) this session. PHP doesn't seem to have any kind of session_abort_write() function. I don't want to destroy the session variables from prior script runs, so I can't use session_destroy()
I tried session_id(""), but that call fails. I could "redirect" the session so it writes to another session, like session_id("trash"), but that would cause a lot of PHP (Apache) connections to try to write to the same session "file", which I want to avoid.
I'm highly simplifying the problem here, we're actually storing sessions in Memcached and this is a complex codebase. So I don't want to be sending unnecessary "trash" sessions to the Memcached server all the time.
From PHP.net,
session_regenerate_id
will replace the current session id with a new one, and keep the
current session information.
session_unset will free all registered variables
session_unregister ( string $name ) will unregister a specific variable
I haven't actually determined if this method prevents writing the session to the session store, but here's the solution I finally used:
session_id( 'trash' ); // or call session_regenerate_id() as someone else suggested
$_SESSION = array(); // clear the session variables for 'trash'.
I'm hoping this has the effect that nothing will get written, but I'm guessing it still will write a blank file, because PHP can't know that sess_trash isn't already there.
If you want to completely avoid writing the session, you'll have to use a custom session handler in PHP and set a global flag to prevent writing the session.
You could probably use something with session_set_save_handler to put dummy functions in for session handling.
<?php
function fakeIt() {
return true;
}
session_set_save_handler("fakeIt", "fakeIt", "fakeIt", "fakeIt", "fakeIt", "fakeIt");
There is session_write_close(). It dumps out the session array to storage and then "closes" it - $_SESSION will still be available and read/writeable, but any changes will no longer be saved, unless you do a session_start() again later on within the script.
I am creating an upload feature that stores a user uploaded file on the server with the user's session-id as its name. Now, I want to keep this file on the server only till that session is active.
So, my question is, how can I determine from the session-id, whether a session is active or expired so that in the later case I can safely delete the user uploaded file.
This I want to do as a cleanup at particular intervals maybe by using a cron job, though I have never used it before.
You can't just rely on session.gc_maxlifetime because after this time the session is marked as garbage and the garbage collector starts only with a probability of 1% by default ( session.gc_probability).
The better approach IMHO is to handle yourserlf the expired data.
You can for instance start the time and save it into a session variable:
<?php $_SESSION['last_seen'] = time();//Update this value on each user interaction. ?>
Later..via cron you can do something like this:
<?php
//Get the session id from file name and store it into the $sid variable;
session_id($sid);//try to resume the old session
session_start();
if (isset($_SESSION['last_seen']) && $_SESSION['last_seen'] > $timeout){//Session is expired
//delete file
session_destroy();
}else if (!isset($_SESSION['last_seen')){ //already garbaged
//delete file
session_destroy();
}
?>
Not tested...just an idea
I'm trying to do the exact same thing. One solution would be to define a custom garbage collector function with session_set_save_handler(). In this custom function you would delete the uploaded files associated with the session and then delete the session from disk. The only problem I see it's that you will have to define the rest of the session handlers as well:
bool session_set_save_handler ( callback $open,
callback $close,
callback $read,
callback $write,
callback $destroy,
callback $gc )
This is easy if you don't rely on PHP to handle sessions. Is there a way to call the default handler functions of PHP from a custom handler function?
Intervals can be made like this - someone opens your web -> php script is running -> it checks if files is time-outed -> delete time-oted files
And no CRON needed :-)
It is nearly impossible to determinate due to lack of information if user closed or not the browser window ( if he don't closes it but turn sleep mode on and come back in 2 days - session is still active AFAIK ) -
only idea to slove this problem in best manner this is to use own session engine with AJAX checking.
I'm making somewhat of a "module" that gets included into another unrelated PHP application. In my "module" I need to use sessions. However, I get the 'session has already been started...' exception. The application that my "module" is included into is starting the session. If I cannot disable sessions in this application, what are my options? I'd like to use Zend_Session, but it seems upon first glance that it is not possible. However, maybe there is another way? Any ideas?
Thanks!
With PHP’s session implementation, there can only be one session at a time. You can use session_id to check if there currently is a session:
if (session_id() === '') {
// no current session
}
Now if there is already an active session, you could end it with session_write_close, change the session ID’s name with session_name to avoid conflicts, start your session, and restore the old session when done:
$oldName = session_name();
if (session_id() !== '') {
session_write_close();
}
session_name('APPSID');
session_start();
// your session stuff …
session_write_close();
session_name($oldName);
session_start();
The only problem with this is that PHP’s session implementation does only send the session ID of the last started session back to the client. So you would need to set the transparent session ID (try output_add_rewrite_var) and/or session cookie (see setcookie) on your own.
Try setting a custom "name" parameter for your application.
The default is PHPSESSID. You can change it to PHPSESSID_MYAPP to avoid conflicts with the other app.
Add the following code before you want to use the Session feature:
#session_start();