Exactly when and where should I use session_start() in PHP?
For example, say I have a login script that sets a session variable to tell whether or not the user is logged in. Must I then put the session_start() at the top of the script, or only right before I actually set the session variable if the login was successful?
<?php
// session_start(); here?
if (login($username, $password)) {
// session_start(); or here?
$_SESSION["username"] = $username;
}
?>
Another case is this, according to w3schools
Note: The session_start() function must be the very first thing in your document. Before any HTML tags.
As others have said, the absolute requirements of what you must do are:
You must run session_start before you read or write to $_SESSION (otherwise it will just be an ordinary array and not saved anywhere).
You must not run session_start twice during a single script execution (page load) unless you use session_write_close to close it in between.
There is an extra rule that technically has exceptions, but is best treated as absolute:
Do not start the session after you have written any output (echo, HTML outside PHP blocks, etc), because PHP may not be able to send cookies to the browser if the server has already started sending the content.
There are two reasons you might want to avoid starting the session:
PHP locks the session when you open it to avoid two processes writing conflicting data into it, so if you have several requests happening at once, you want to avoid them waiting for each other unless they really need to. For instance, if you're responding to an AJAX request, and don't need any data from the session, don't open it.
As mentioned by symcbean, there is some cost to creating a new session, so if your site is busy with either legitimate or malicious traffic, you might want to serve some landing pages or error messages without starting it at all.
After that, it becomes a matter of style and architecture, but the rule of thumb that covers most of the above is "as soon as possible, if you're sure the page needs it".
Unless you have output buffering enabled, the session_start() must come before anything other than headers are sent to the browser (as it sets a cookie in the header).
It must come before you attempt to reference the $_SESSION data.
In your example there are no html tags being output before either instance - so both would work.
There some cost to opening a session, so if you are doing additional, non-session based validation of the request, then deferring session_start() till these checks have passed does give you a bit more resillience against DOS attacks.
Starting the session at the top of the page is most of the times the best. But if you don't need the session for the whole document/code, you could always put it, as in this example, after the if() clause.
The session_start() function can go anywhere in your code. You should just place it at the beginning of your document for consistency and call it a day. If you have a separate database or config file you are including on all your login/database driven pages, you should place it in there so you don't have to recode it into every page.
Related
In my PHP application, I heavily use sessions to save information during redirection:
Saving information on category, so the correct tab and/or form is displayed after a redirection
Saving information when you are logged in to access some functionalities
Saving information on errors and warnings so they are displayed once all back-end operations are done and you are redirected to the main dashboard
In implementing that I called session_start in about 40 scripts, but outside of occasionally calling unset() on a $_SESSION variable I don't close the session in any way.
Now, while I was investigating performance issues on my server, it came to my attention that an underuse of session_write_close() might be the issue (even if the question was on an apache linux and my web app is hosted on a wamp server) and that in the end, even if it is not the cause, it might be sensible to try to close the session as soon and as often as I can.
I'm wondering how do I identify the points where I can safely destroy/restart the session? And what would be the best way to do that?
Keep in mind I want the number of opened session not being an issue, so I want to be sure to keep it at a minimum.
Typically we do not close session unless it is very important since session would be closed as soon as browser is closed.
Due to lack of knowledge of your application we are not in position to comment on exact need to close session in script. Considering the events you described it might be better idea to use cookies in certain situation like "Saving information when you are logged in to access some functionalities". Regarding error and warnings; you may like to remove some session variables after you have displayed messages on dashboard page.
For "Saving information on category, so the correct tab and/or form is displayed after a redirection" you can consider using parameters in URL to show desired tabs instead of using session variable.
In case you plan to use session_write_close() then in that case you would need to do session_start if you need access to session in the same script a second time. Use of session_write_close() is only to resolve locking of session in case two scripts try to access same session at same time. So you may like to describe if it is the case with your application or not.
It seems that ob_end_flush() causes implicit session closing. Is this intended behavior? I suppose the answer is 'yes', but can I somehow prevent it?
Here's description of the problem I've encountered. I'm using framework that uses custom session handler, I don't think it matters in this case, but just for information. The actual problem occurs when at some point in framework code ob_end_flush() is called. By logging custom session handler calls I notice that session write and close called in this case. It's so implicit that I cannot even debug it with Zend Debugger, only log it with error_log. So, after ob_end_flush() interaction with session still continued (I know, that may be wrong, but still this is the case) and in that situation, when previous session is already closed, new session with new id is started. New session has new id because cookie is not set at the moment. So, as the result, I got two separate sessions with two different ids.
The best solution for me would probably be disabling that implicit ob_end_flush() behavior, but I will accept any answer.
Thanks in advance.
While a slightly indirect answer, it's common practice (and sometimes recommended practice) to start an output buffer with the purpose of buffering the entire request. Doing so allows you to continue to use session and/or set headers (including redirects) long after you start "outputting" content. This should take care of your implicit session close issue. Just add an ob_start() call to the top of your bootstrap.
I´m having some serious trouble debugging this particular problem and I hope someone has a clue what i´m doing wrong.
I have a Custom CMS system working that uses Paragraphs as building blocks that get updated using Ajax(prototypejs) calls and functions that parse the HTML chunks in given order, clean them up and save this data in associative arrays in a Session variable.
Users log in, Session is created and I can check for this session without problem in every page I need it. The system works directly on the definitive websites, so the user can see his updates on realtime and browse the site as a normal user would do, but editing.
So, nothing new here. But here is the weird thing.
Enduser site on edit mode(admin user logged in): path "/"
After the logged status is verified, a function processes the editable content and saves an associative array to session, it also starts some javascript objects for editing every paragraph. Data is actually saved, I can use an external script to check if it´s there after this php script ends.If I load a new page(new content), Session gets updated with new data)
Admin User modifies a paragraph using an Inplaceeditor and this HTML chunk is send via Ajax to a php script that starts the named session, reads the present session data, checks if a paragraph should be modified, appended or deleted and reassigns values to existing array keys in $_SESSION. if i make a var_dump() o print_r to $_SESSION after assigning new data is there.After that the script echoes the processed html, and ajax updates the original paragraph on the calling page.
This script is in /admin/cms/...etc, that means at least 4 directories inside the root of the site.
When the script ends, I check using the same session dump script to see if data was really written/commited, but no, $_SESSION has only the original data from the calling page.
Same ID, same session name, same session_start() but no data gets written.
This whole operation is very quick, so I though it could be a speed problem, scripts ends before session_write_close can make his work.
But if I add a new key to $_SESSION array and put some data there, data gets updated and written. If i don´t output anything on this script and just process data and set session variables it also get´s updated and written.
It´s like some members of $_SESSION array are getting blocked to update.
What i did to track this error and what i´m sure i´m not doing wrong.
1.- register_globals are off of course
2.- session_name() and session_start() are always present and in the given
order. I used to have multiple
session_start() -close on a same page
to use several named sessions, but to
refine the problem this is not longer
so.
3.- I use session_write_close() after session data is processed. Also
tried without, letting php decide
when to commit data, but no luck.
4.- I`m using only cookies for SID.
5.- sessions are stored on /tmp, i can see the data getting updated.
I also tried using a custom save
handler on DB, but same problem,
"_write" got only called when no output as present.
I searched php.net, stackoverflow, google, etc for this subject. I never ask without investigation, this is my first time in many years...but it´s just so unlogical it must be something tiny a haven´t thought of.
The most weird thing is that when I just process data without output $_SESSION gets updated ok. But if i modify this script afterwards by adding the output and try again, instead of just having the new(last) value present I get the original value back, the one created by the calling page at first place, sometimes after playing around a few times! PHP can´t cache values between scripts or?I dont have globlals on.
I´m really clueless. This system worked flawless on PHP4.3, since i´m using 5.3.3 for two moths my users where caliming data where getting mixed up, so i checked and yes, there are serious problems. Today I updated to (5.3.6) and I can´t get this session values commited.
Script code called via Ajax:
<?
session_cache_limiter('nocache');
session_name("CMS_ses");
session_start();
include('../htmLawed/htmLawed.php');
include("utils_cms.php");
include("../../../php/utils_array.php");
$value=$_POST['value'];
$editorId=$_POST['editorId'];
$clase=$_POST['clase'];
$editorId=str_replace("pre","",$editorId);
$value=html_entity_decode(stripslashes($value),ENT_QUOTES);
if (strlen(trim($value))==0)
{
die();
}
$value="<div id=\"$editorId\" class=\"$clase\">$value</div>";
$newXHTML=$value;
$retorno=CMS_nuevoBloque($newXHTML,$editorId);
$_SESSION['data']['CMSeditores']=$retorno[1];
$_SESSION['data']['CMScont']=$retorno[2];
session_write_close();
print_r($retorno[0]); //Offending part...without everything works
?>
really nothing strange here....main page code is even simpler, no strange php directives, etc.
Here is the header of the caller page
include 'php/db.php';
$len=$_GET['len'];
$sec=$_GET['sec'];
$cont=$_GET['cont'];
$admfin=$_GET['admfin'];
$fecha=$_GET['fecha'];
$token=$_GET['token'];
$cur=$_GET['cur'];
$PHP_SELF=$_SERVER['PHP_SELF'];
session_cache_limiter('nocache');
session_name("CMS_ses");
session_start();
$passvar='';
unset($adm);
if ((!empty($_SESSION['cms_logged'])) and (!isset($admfin)) )
{
$nivelpermisos=$_SESSION['cms_logged_group'];
$useractual=$_SESSION['cms_logged'];
$adm=1;
}
elseif (empty($_SESSION['cms_logged']))
{
unset($useractual);
}
//.........rest of the code
UPDATE: I did late night tests and found someting i don´t understand.HElP please:
It has not only to do with Sessions but also with Mysql Querys. Same code, but instead of trying to write to $_SESSION array i made a simple update to a Innodb table using the session_id. When i Output some code, the update does get executed,(i can output the query string and no mysql_error() or notice) problems, but checking the database the row doesn´t get updated. Letting the output out if the script and Query does get commited. Only common thing is sessions are started and output is made.
I restarted Apache, etc(who knows) but no luck. Then i made something really stupid, because this is a server side thing. I changed my browser to Firefox(using safari) and everything works! Ok, recheck, back to safari, nothing works. Both running side by side, same issue. PHP is server side, how can different browsers handle code different, can a browser say to apache rollback, request not handled or call the same script twice without notice(checked safaris developer console and the script is called only once) ? Can safari resubmit data silently because it "thinks" ajax failed? I checked headers using firebug and Safaris developer tools , nothing strange but whenever i make a Ajax call with safari, the caller page reloads data(Aka conection to server...).
I really don´t understand nothing.
I had a similar problem to this (if I have understood correctly). I needed to force session data to be written (for a custom session driver) after scripts have finished running. A shutdown function can be registered which should run after scripts have finished.
Maybe this will solve (or help you to solve) your problem.
http://php.net/manual/en/function.register-shutdown-function.php
Thank's for your help. I was doing everything in the right order and still session data was not being written. Session names where necesary because sometimes we test many sites on the same domain using the same custom CMS. So, finally, after making lots of test and no luck, i found that register globals was active on this server(we never use it, code was written having this option off in mind of course), but it messes with sessions!. Switching this off made a huge change. No more problemas. I also made a custom session handler in DB, so i could track the problems in an more centralized way.
Conclussion: Never use register globals + named sessions, an complex data in sessions.
Anyway, i will give this issue more time and more tests. Ajax calls are also sometimes too fast, i had to put a sleep command so writing the session data was really done.Thanks
I am not sure but few suggestion i think may be helpful.
delete session cookies before refreshing the page for testing purposes :)
Ensure that you're not assigning any arrays with a key containing the pipe character (|). This will prevent the session data from being serialized and saved.
Do session_regenerate_id(true); many cases session_write_close doesn't seem to matter with out session_regenerate_id. or just do session_start() after session_write_close() if you are relying on SID ; and in your case i think this is what is causing problem to you as you are ending the current session every time and not re starting it for the next page. hope u get my point. Further more To Make sure data is actually flushed out to the browser use ob_end_flush();
i could not understand the connection between
$_SESSION['data']['CMSeditores']=$retorno[1];
$_SESSION['data']['CMScont']=$retorno[2];
and
$nivelpermisos=$_SESSION['cms_logged_group'];
$useractual=$_SESSION['cms_logged'];
i think you need to paste some more code where the data part is causing problem instead of admin login part.
i hope this helps you.:)
Is there any reason you're establishing the session name twice? I've had issues in the past where I would establish the session without a name, then another piece of script (not mine) was naming the session. Even at the end of the script I was able to print out the session variable, but once I went to a new page my session had been forgotten. It wasn't until I copied the name included in the 2nd script into my session call that it was solved.
Check that there's no other session names being used; also, maybe try only naming the session once, at the first call to the session?
Question: Are you calling session_start() first thing... before ANY output to the browser and before any variables are assigned?
Sounds silly but give it a try.
Also, why are you using session names? Really not necessary unless you have a lot of session variables with the same name serving different purposes and if thats the case then you need to fix that first!
I had a similar problem but it was having with ie few years back. IE manipulates the header on its own way and that causes strange php bugs that you can find in php.net archives.
#Diego Pino Navarro, please see this help page and find Safari and it's issues with php.
I also found "Safari "forget" http-authentication's logon-information".
the question is really simple, but i searched it many different ways and the results were not related to my question.
so if i have a session variable in a php file if i open an html page after that and then a php file again, will i be able to retrieve the data ? or do they all have to be adjacent?
I tried php->html->php but i couldn't get the variables on the other side. maybe Im doing something wrong.
Thanks in advance
Not 100% sure what you mean, but if by "open" you mean in the browser, the calls do not need to be adjacent. You just need to do a session_start() in every PHP script in which you want to use session data.
Adjacency is not something that is really relevant for this question.
in PHP way of things, sessions are essentially files that contain serialized data on the server. The browser that called a script containing session_start() call receives a special token that identifies the session on the server, and it is normally (though not necessarily) stored as a cookie.
This effectively means that any php script that uses session_start() and receives a session id (via cookie or otherwise) will read and could use session data, unless it was removed from the server file system between the calls, or the session has expired (frankly, I'm not sure whether PHP removes the expired sessions on the server side).
Accessing anything outside of this model with the browser (html page, or even other sites) will not affect it in any way, unless these actions change or remove session id.
yes...session variable can survive php->html->php.
But on every php page ...very first line should be session_start()
This easy way (I guess): Set a cookie storing the session ID on the first php page. This way, every other php page can access the session ID and use it to restore the stored data, not matter how many (even foreign) pages were in between.
Context: I was going to build app using mod_rewrite (front page loading child pages), but got stuck on loading session_enabled pages from the front controller page.
Problem: The problem is that I use session_start() call twise, PHP page stops responding. Which is strange, the session_start function is harmless and they are called on different pages.
I've narrowed down the problem to this sample:
child.php file:
parent.php file:
Call to parent.php will make browser load infinitely. As soon as you comment one of session_start() calls - it loads instantly.
What is the source of the problem?
I badly need session-enabled pages.
PS I can work it around by including pages, but they rely on URL params, I would like to avoid fixing them for sake of some kind of parameter proxies.
You need to call session_write_close() once you no longer need to write to the session. Currently as both your scripts have the session open for their entire duration, you will only be able to have one running at a time.
From the manual:
Session data is usually stored after
your script terminated without the
need to call session_write_close(),
but as session data is locked to
prevent concurrent writes only one
script may operate on a session at any
time. When using framesets together
with sessions you will experience the
frames loading one by one due to this
locking. You can reduce the time
needed to load all the frames by
ending the session as soon as all
changes to session variables are done.
Besides that only one session can be used at a time. You need to call the session_regenerate_id function to generate a new ID:
if (session_id() != '') {
session_write_close();
}
session_start();
session_regenerate_id();
Otherwise the parent’s session ID would also be used for the child’s session.
Try using session_write_close() before loading your child page.
You can also check if a session is already started and only start a new one if not:
if (!isset($_SESSION)) session_start();
Having two session_starts() in your script is a bad thing anyway.
Why don't you just start the session on your parent.php file (and not child.php)?
Or just child.php and not parent.php
It's a good idea to have one page that is included by all other pages that initializes everything (SQL connect, session start, etc). And then include that page on all others.