I am writing a PHP website. I have a $_SESSION['id'] that hold the username id of a user, which I will use this value later on in my scripting. However, I notice that the ID changes as I surf the site.
Is id reserved in any way? Or, should I change id to something else?
This problem is happening whenever I click on a button several times. I am 100% sure that I'm not altering $_SESSION['id'] beyond the initial login.
Could someone please help me understand what is happening, and how it can be fixed.
I am going to assume you already use session_start, if not see the other comments :P
If you have register globals on, you may be seeing behavior like that if you use the variable $id in your code. As a test, try:
<?php
session_start();
$_SESSION['testing'] = 'Foo';
$testing = 'bar';
die($_SESSION['testing']);
?>
Reload the page a couple times. If bar prints out rather than Foo, that may be your problem. You'll probably want to make the session variable name something that is less likely to get used elsewhere, or (more correct) turn off register globals.
make sure you start the session - look at session_start();
Make sure you are calling session_start() at the very top of the page(aka before ANYTHING else).
This may be causing the screw up.
A very quick rundown as to why you need to do this:
Most of the time a session id(different from $_SESSION['id'], don't worry) is stored via cookie. The cookie values are sent via the response headers, which needs to be the first thing that is sent back to the client. So if you are outputting ANYTHING before calling session_start(), you are actually forcing php to send the response headers. This will cause the response headers to NOT contain the cookie session value, thus not being able to properly use the session.
Related
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.
As silly as it sounds, I'm baffled by this behavior:
In my PHP code I am calling session_start(); before anything else (not even a space before it is called). I can test this by setting a session variable and then echoing said variable.
If I run the following code on one of my pages I get an expected session ID back, but if I run it on one of post pages used for ajax then it comes up empty. Only sessions that I set on the ajax post page specifically can be seen, not session variables set from another page.
$a = session_id();
var_dump($a);
I know I'm going to get responses telling me to make sure my session_start(); has been called from the beginning, but I swear up and down it is (if it wasn't, sessions wouldn't work locally on that page).
What in the world could be causing this strange behavior?
FWIW, adding ini_set('display_errors', 1); error_reporting(E_ALL); doesn't give me any info other than telling me I have an undefined variable when trying to dump a session var that was set from another page.
How do you navigate between the pages? If you're using header, the session data isn't always written before leaving the first page. I had to use
session_write_close();
header('Location: page2.php');
If you say that session_start() is implemented correctly and $a shows on some pages but not on specific pages, I would say it is most likely because session variables are super global and maybe on those pages you have a global variable $a.
This ended up being caused by my /tmp partition being full. I have a headless dropbox installation on this server and it decided to update itself overnight last night to a new version and not clean up behind itself. I should have gotten a notification that the /tmp partition was full but I did not for some reason so I didn't even think about it being the cause.
Let this be a warning to others who find they have the same problem I did. I'm still not entirely sure why I was able to set a new session variable on the problem page or even set the session vars for the other pages to begin with if the /tmp was full.
I appreciate everyone's willingness to help out though!
Short and sweet, I need to have a variable NOT be unset after a page has finished loading. I've used a file to store the value, and I've used a MySQL table with 1 record, and updated/read from that, but I want something cleaner and simpler. Any ideas?
Some people misunderstood the question, so here's an example. At the top of my page, I would have some code such as:
$_PERMANENT['hits']+=1;
print 'Hits: '.$_PERMANENT['hits'];
Note that this works across multiple clients, so it's not $_SESSION.
I finally found the answer: apc_store et al
Use the $_SESSION, that's exactly what it's for. This either requires the user's browser has cookies on, or that you format links to maintain the session id.
At the start of your pages, use session_start() - only do this once, and it must be before content is written as it needs access to the header area.
session_register() is deprecated, so just do a $_SESSION['key'] = $value; and the next page load within that session will have access to the value via: $value = $_SESSION['key'];
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".
I know that through cookies or something like that you can save things in the user's PC/browser. It would be useful for me to save the users location after he typed it, so I can adjust all the info accordingly. My question is, what is the best way to do that and how long is the info saved? And finally if I wanted to save for example the word "pizza" and access it later how do I do it?
Thanks. I know it's a lot and all very noobish.
A simple example:
page1.php
<?php
setcookie('favorite_food', 'pizza');
?>
I just set your favorite food to "pizza". Want to see?
page2.php
Your favorite food is <?php echo $_COOKIE['favorite_food'] ?>.
The function for setting is setcookie. You provide a name for the cookie, the value (contents), when it should expire (time() + $number_of_seconds_until_it_should_expire), and then some other options regarding where on your site this cookie can be accessed. If you give no expire time, most browsers will delete the cookie once the browser is closed. The PHP setcookie documentation is much more detailed and is a good starting point for any more specific questions you may have.
It can later be accessed via $_COOKIE['name_you_used_when_setting'].
A general note: always remember that, when dealing with cookies, you can't trust the user not to change them or delete them at any time. Use them only for convenience, and never for something like setcookie('user_is_admin', 1) or setcookie('user_is_banned', 1).
Save it in a cookie. It's saved for as long as you specify, unless the user clears their cookies. As for setting it, take a look at PHP's setcookie() function