PHP Sessions' internal mechanics - php

From the manuals, I draw that when a php session var is set, it is written to a text file in the session_save_path folder.
I am just curious to find out if this happens as soon as the interpreter hits the line with the session variable or does it ( writing to the text file ) takes place when the PHP interpreter exits processing the file?
For example, if I were to set and update a session variable in two consecutive lines, (as in the example I gave below), does the PHP interpreter saves the files twice back to back?
In other words, which code snippets has the right commenting?
$_SESSION['my_variable']=1; // writes to the session text file
$_SESSION['my_variable']=2; // writes to the session text file again
die(); //
versus
$_SESSION['my_variable']=1; // updates the session file contents in the memory
$_SESSION['my_variable']=2; // updates the session file contents in the memory
die(); // writes to the session text file

Data is written to file if:
session_write_close() is called
the script execution is finished
So provided that you don't do 1), your second assumption is correct.
Writing to the file every time a variable changes would be VERY expensive, because generally speaking accessing and writing to the disk is slow, hence why PHP won't do that. It should be noted however that caching systems such as memcache or redis will store changes as they happen, so it can be a good idea to rely on them when PHP sessions do not suffice in terms of reliability.

The second one, the $_SESSION[...] = ... they just set the value inside your $_SESSION array and die() triggers this function:
session_write_close
(PHP 4 >= 4.0.4, PHP 5)
session_write_close — Write session data and end session
Report a bug Description
void session_write_close ( void ) End the current session and store
session data.
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.
http://nl.php.net/manual/en/function.session-write-close.php

So, I tried to test this by doing the following.
test_1.php
session_start();
$_SESSION['my_variable']=1;
sleep(20);
exit;
and
test_2.php
session_start();
var_dump($_SESSION);
Here are the cases I tested:
Executing test_1.php then quickly executing test_2.php.
Result: test_2.php froze until test_1.php finished sleeping.
Executing test_1.php, removing the PHPSESSID cookie and THEN
executing test_2.php.
Result: test_2.php executed right away with no freezing (test_1.php in the meantime was still sleeping) and printed an empty array.
Novice conclusion:
PHP opens a stream to the text file related to that session until the script has finished executing and then it "commits" the changes. (I'm not an experts, so my terms might not be accurate)
Edit: yet another useless test due to not consulting the documentation
but as session data is locked to prevent concurrent writes only one
script may operate on a session at any time

Sessions will be written in cookies or whatever storage you choose only after flushing the setter page. ex:
having pageA and pageB :
setting in pageA :
session["foo"] = "bar";
session["foo"] will be available to pageB only after:
leaving pageA to pageB
or
leaving pageA and refreshing pageB
that considered, the best definition IMHO is the second one.
Happy coding!

Related

PHP script called by ajax can't execute start_session()

I have a script A that calls session_start() at the top and creates some session variables.
Then the script makes an ajax call that invokes script B:
$("#galleryContent").load("B.php", {op : 'get_thumbs'
},
function() {
$('.galleryThumb').draggable(thumb_dragOps);
}
s);
B needs access to the session variables script A set up so it does a session_start() to try to get at the variables. But B's session_start() hangs.
Am I doing something wrong here?
Thanks
It's due to locking; PHP locks the session file while it is writing to it. To fix this, close the session file when you are done modifying session variables using session_write_close().
I have had exactly this problem in the past, and locking was the problem. Just be sure to explicitly tell PHP you're done modifying the session using session_write_close(), and you should be fine.
From the documentation:
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.
Note: You can also set up a custom session handler and avoid this file-locking problem entirely by storing session information in a database. At any kind of scale, this is pretty much a necessity.

Requests from same client being queued in Apache, PHP stack [duplicate]

session must be synchronized. When A writes/saves to session B or another A is put on wait. Which is a must for file based session handling.
But once A has loaded the session (but now saved its modifications) B should also be allowed to load the same session. because loading will open the file and bring the file contents in memory and close.
Is there any reason to block all other scripts during the whole time A loads session and A saves the session. can't the synchronization be done only with save handler ?
So two PHP scripts can never work concurrently If they share the same session.
for example seslock.php
<?php
header('Content-Type: text/plain');
session_start();
if(isset($_GET['wait'])){
sleep(30);
echo "waiting\n";
}else{
echo "No Waiting\n";
}
?>
done
visit seslock.php will respond immediately but seslock.php?wait will take 30 seconds to respond. But the problem is if you request seslock.php?wait first and only seslock.php second. event the non-sleep block will ask you to wait for 30 seconds too.
Why it block is not my question. I am asking why it blocks start to save ? instead of blocking only save ?
Possible duplicates:
How does session_start lock in PHP?
Why does session_start cause a timeout when one script calls another script using curl
session_start hangs
How to kill a PHP session?
... And many ;)
Edit
The reason why it blocks is because the session file is being read and it might be modified at any point of time when the first script is running, hence the lock.
The remedy to this could be a session_write_close() as pointed by this post
How to prevent blocking php requests, by Konr Ness
The default PHP session handler is made to serialise session changes for each session id. This has the benefit of a guaranteed consistent session state across your scripts.
You can give up this advantage by running session_write_close() right after session_start(). This also makes your session read-only though.
Alternatively you can write your own session handler without locking.

Pages hang when another page from same site is loading

Seeing some strange behavior in my application. Any time I have a long running script waiting for a response in the browser, any other page in the application will spin/hang after a click (even for very simple//static pages) until the original page finishes loading. This is a PHP5.3 based application using native PHP sessions on Apache 2.2.x.
This happens in multiple browsers in all our dev, qa, and production instances. I'm not sure where to start looking. Any advice?
Get all the data you need from the $_SESSION, and call session_write_close() before you are going to do something that takes a long time. Due to a PHP script still being active with that session, it locks the session (after all, it may write some data to that session that the next request needs).
If you need to write something to the session after you've done your long job, you can just call session_start() once again (provided you've not generated output yet), write to it, and after that the script may end, or maybe you repeat this cycle a few times.
Also, don't call session_start() if you don't need it, I see you mention 'static' pages. If a page does not need session data, avoid the overhead & locks it creates.

PHP session_start serializes and blocks all others sharing the same session

session must be synchronized. When A writes/saves to session B or another A is put on wait. Which is a must for file based session handling.
But once A has loaded the session (but now saved its modifications) B should also be allowed to load the same session. because loading will open the file and bring the file contents in memory and close.
Is there any reason to block all other scripts during the whole time A loads session and A saves the session. can't the synchronization be done only with save handler ?
So two PHP scripts can never work concurrently If they share the same session.
for example seslock.php
<?php
header('Content-Type: text/plain');
session_start();
if(isset($_GET['wait'])){
sleep(30);
echo "waiting\n";
}else{
echo "No Waiting\n";
}
?>
done
visit seslock.php will respond immediately but seslock.php?wait will take 30 seconds to respond. But the problem is if you request seslock.php?wait first and only seslock.php second. event the non-sleep block will ask you to wait for 30 seconds too.
Why it block is not my question. I am asking why it blocks start to save ? instead of blocking only save ?
Possible duplicates:
How does session_start lock in PHP?
Why does session_start cause a timeout when one script calls another script using curl
session_start hangs
How to kill a PHP session?
... And many ;)
Edit
The reason why it blocks is because the session file is being read and it might be modified at any point of time when the first script is running, hence the lock.
The remedy to this could be a session_write_close() as pointed by this post
How to prevent blocking php requests, by Konr Ness
The default PHP session handler is made to serialise session changes for each session id. This has the benefit of a guaranteed consistent session state across your scripts.
You can give up this advantage by running session_write_close() right after session_start(). This also makes your session read-only though.
Alternatively you can write your own session handler without locking.

Does every access to $_SESSION immediately involves an i/o with the file system?

Every time I access data in $_SESSION, Does it immediately update the session file on the disk, or just once when the process goes down? Or every n bytes of data change (flush)?
This question is not necessarily about the specific file session handler, but every handler. (Does every touch in session immediately invoke an I/O of any kind, beside the storing of a normal variable in memory).
As Matt wrote, it writes at the end of script execution by default. You can read about it here in session_write_close()
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.
It writes it and the end of the process on my setup. I made a new _ session_ write_method:
public function _session_write_method($id, $sess_data) {
var_dump(file_put_contents('/var/www/public_html/testing.txt', serialize($sess_data)));
return(true);
}
and then:
$_SESSION['foo'] = 'bar';
while(true)
I executed the script,waited a few seconds and then ran 'sudo kill' on the process id. It did not write the serialized data to the file. I ran it again without the infinite loop and I got: int(22) at the very bottom of the page and testing.txt was successfully written to and contained: s:14:"foo|s:3:"bar";";
Depends on the handler. You can write your own handler to make sure it only happens as often as you like if you want to be absolutely sure about the behavior. There are 6 callbacks used to manage session variables. The one called "write" does not have to perform any real I/O and writing the session file could wait until the call to "close". It is an implementation detail that, as I said, depends on the handler.

Categories