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.
Related
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.
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.
Do I have to explicitly close session before redirecting to another page?
session_start();
if (isset($_SESSION['login']))
$login = $_SESSION['login'];
else {
// is session_write_close() necessary here?
header('Location: /login');
exit();
}
Is there any way to tell PHP to close the session, but also to not bother saving session data? (Something like session_discard_close())
It's very hard to answer this anymore fully than "no".
However, if you read the PHP manual page for session_write_close you'll see that it states:
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.
As such, in some edge cases the answer is "no, but it might be faster if you do".
No, it is not necessary. The session will be automatically closed at the end of the request. 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.
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.
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.