The situation:
I have a site with multiple pages accessible through the menu, after login.
On the dashboard page (the page you see right after login), there is a AJAX call getting the data from the PHP-Controller (zend framework). This call does about 20 queries to 2 different databases and a lot of data manipulations. It can take up to 5 seconds to load everything. So far, so good!
My problem:
When I go to another page through the menu, right after seeing the home page, the ajax call gets cancelled, and a new request is send to a new PHP-Controller. But because I'm working with php-sessions (through the zend-framework), I'm not able to do a new request before session_write_close() is called (at the end of the long-taking AJAX request). Is there a possibility that the previous call gets cancelled?
A not decent solution:
Right now, I've called session_write_close() at the beginning of my AJAX request, and this fixes the problem. Afterwards I still read from the session, but I've read, and confirmed that this is not an issue. Nevertheless, calling session_write_close() is not the prettiest thing to do, and I'm working with a few guys on this project, which has a lot of files and code paths, and won't be finished in the next 5 years... So I can't use session_write_close(), since this would not be maintainable. Especially because when you write to the session, PHP would not throw an exception. The data would simply not be saved.
So my question is:
Is there a decent alternative to session_write_close(), that let me interrupt/cancel an AJAX call (PHP-wise), to instantly go to another page, or is there a possibility to change a setting so that PHP would throw an exception when trying to write after session_write_close() is called?
Thanks In advance!
One option would be to store the session values in a database. So once you have the session_id you can read and write to the DB with updated values. It would look something like this:
$session_id = session_id();
session_write_close();
$query = $dbh->prepare("select * from tbl_sessions where session_id=?");
$result = $query->execute(array($session_id));
$values = $result->fetch();
$session_values = json_decode($values->data); //data would be a text column with a json or serialized array
//you could update any values then update tbl_sessions if you needed
Or you can override the default session functions like in this answer: set session in database in php
Or as in another answer you can close and open the session as needed:
https://stackoverflow.com/a/10046611/1401720
Related
So the question is a little complicated, let me explain. My page code is running like this:
User enters query in the search field and clicks submit.
1.1 jQuery loads a new body to display progress data.
1.2 jQuery calls process.php via AJAX and supplies query as the argument.
1.3 jQuery starts setInterval periodic update to grab progress data, stored inside $_SESSION['prog'], and displays it.
When process.php finishes, jQuery stops periodic update, displays final information and calls AJAX to clear the $_SESSION['prog'] variable.
At the moment progress data is stored inside one variable, which is fine as far as different users are concerned (because of the different sessions), but if the same user were to make multiple requests at the same time, the $_SESSION['prog'] variable would be cross-overwritten.
So far I have thought of two possiblities to distinguish data for each request from the same user (same session)
Have jQuery generate some random string and send it together with query (and hope to avoid colission, although that would be unlikely)
Make 2 AJAX calls, first one requesting new_request_id, the second one sending query and new_request_id as parameters.
Have AJAX return something from PHP before is finishes(completes).
I need to connect each browser window (each request) with each running process, so I cannot send back new request ID after the request has been submitted, because I wont know which data to pick up with jQuery in the browser window. Btw, I will change $_SESSION['prog'] to $_SESSION[request_id] -> request_id is what I'm looking for.
It (request_id) could be last_insert_id(), because im creating new DB entries for each valid query, but I don't know how to get it back to each different user window.
I need advice here. Only just begun to code in PHP, AJAX and jQuery, don't really know much about sessions. How should I solve this problem?
Sorry for the lack of code, I will paste is at request.
You could add a unique ID to each request in addition to the session ID. eg. uniqid() in javascript/jquery?
You need to differentiate them somehow. For example use a unique ID autonumber field. MySQL has last_insert_id() which is very useful and handles concurrent requests correctly.
Avoid using Session variables in Ajax requests. Send them with GET (or POST) instead. Even if calling Session_start(); in the Ajax request and getting $_SESSION['prog'] from there, results can be unexpected.
Background:
I'm developing a website tracker using javascript. Here's how it works:
1) A user visits any domain the tracker script is on "anydomain.com". The script makes a successful ajax call in the background to my master domain "masterdomain.com".
2) When "masterdomain.com" receives a request, the following PSEUDO code is run. It works by checking for an existing session and if one doesnt exist it creates a new one.
The first call appears to be fine because I am able to receive a session ID in a response. However, each successive call to "masterdomain.com" creates a new session. AKA the server doesn't find the "should be" existing session.
Sample PSEUDO Code:
if(session exists)
{
// update timestamp for session
}
else
{
// set a new session for visitor
}
// load template
api(array("accepted"=>session_id),callback);
Some Quick Facts:
1) This does not appear to be a same origin issue (as I am able to communicate with the server fine).
2) I have tried this with cookies/sessions both appear to not be working.
3) I am using codeigniter (sessions are set not to expire on page close). I have also tried using/not using database sessions).
This problem can also be solved if there is another way to uniquely identify a user each time a page loads on a server (not using IP).
Any help would be greatly appreciated as I'm about ready to tear the rest of my hair out of my head!!!! :(
This answer is incomplete in that you'll have to do some additional research, but the easiest way (which is not actually particularly 'easy') to do this is to use Javascript to place a hidden iframe to masterdomain.com, and set up iframe communication (e.g. using postMessage) to retrieve the session from that iframe to your page.
With AJAX calls you can only send/set session cookies if the URL you're calling is on the same domain as your calling script. I think you should create an iframe, call ajax from within and it should work fine. By the way, I have no idea what you are trying to track.
How reliable is a method of setting variables into a session and then retrieving them on another page?
I have a script where users drag and drop elements on a page utilizing jQuery UI. I record transactions using AJAX, however, sometimes I get results missing project ID, or to be exact I get 0. I set this ID into a session variable when users first get on this script page. The page has an included JS file with my functions and from there the transaction data is sent to an AJAX page where I store transactions into my db. Because the project ID is the same I get it from my session. It is not a consistent error, happens only once in a while, but it bothers me a lot.
Why is it happening randomly? And how can I fool-proof my code?
UPDATE: OK, it seems it's something else that may be interfearing with that particular session ID.
I do have session_start(); on every page where I use sessions and I set them the same way I set all my sessions: `$_SESSION['project'] = $projectID;
Back to debugging...
Yes, you can rely on PHP sessions. If you are getting odd results, it seems like your going to have to debug your code until you find the issue.
From a security standpoint, can someone give me a step-by-step (but very simple) path to securing an ajax call when logged in to PHP?
Example:
on the php page, there is a session id given to the logged in user.
the session id is placed dynamically into the javascript before pushing the page to the client.
the client clicks a "submit" button which sends the data (including the session id) back to the php processing page.
the php processing page confirms the session id, performs the task, and sends back data
I'm stuck on how (and whether) the session data should be secured before sending it through an ajax request. I'm not building a bank here, but i'm concerned about so many ajax calls going to "open-ended" php pages that can just accept requests from anywhere (given that sources can be spoofed).
PHP can get the session data without you having to send a session ID via javascript. Just use the $_SESSION variable. If you want to check if a session exists you can just do
if(isset($_SESSION['some_val'))
//do work son.
You'll need to use JavaScript to asynchronously pass user input back to the server, but not to keep track of a session.
Don't send your session data with javascript.
You don't need to (in most cases).
Just post the data with javascript and let PHP retrieve the session data from... the session.
Depends on how you setup your session data.
One simple example would be you have a session called username.
When PHP gets the request from javascript you can do: $_SESSION['username'] to retrieve the sessiondata.
This is a very simple example just to show how it can be done.
As noted above, you don't need to send any session identifiers out with your javascript, to the server an AJAX request is the same as any other request and it will know your session just fine. So basically, just don't worry about it, it's already taken care of.
It's another part of your question that worries me.
i'm concerned about so many ajax calls going to "open-ended" php pages that can just accept requests from anywhere
It worries me too; you shouldn't have any "open-ended" PHP pages hanging around at all. Every public .php script should have authentication and authorisation done. The easiest and most maintainable way to achieve this, IMHO, is to have a single controller script (e.g. index.php) that does authentication and authorisation then sends the request to an appropriate controller. Aside from this controller, all other scripts should be outside the document root so that they cannot be called directly.
This means that you only ever have to worry about authentication and authorisation in one place; if you need to change it, it only changes in one place. It means you don't need to worry about accidentally leaving some executable stuff in some library PHP file that's not meant to be called directly. It means you don't need to shag around with mod_rewrite rules trying to protect .php files that shouldn't be in the doc root at all.
I have a list of "online users", which I refresh every 30 seconds with Ajax.PeriodicalUpdater from prototype.js.
There is an issue, that if a user has two tabs/windows open with the site, logs out in one of them, the PeriodicalUpdater is not canceled.
This means that PeriodicalUpdater updates my block element with the entire login page, as I have a restful authentication, that redirects to that.
I am using PHP sessions, and I really cannot get my head straight on this one.
Can any of you guys point me in the right direction?
I would consider changing the method that returns the results so that it doesn't require an authenticated session to access it, but it returns valid information only when there is an authenticated session. Otherwise, it returns a value indicating that the updates should cease and a suitable message for display in your online user's block. This would mean that you'd probably need to return JSON instead -- not a bad thing -- and either combine it with an HTML snippet as part of the JSON or simply construct the HTML on the client from the JSON data (better IMO since the view is the correct place to do mark up).
When creating the PE, keep a reference to it:
// At global scope, or ideally if you have a namespaced object, use that
var thePE;
// Where you create the PE
thePE = new PeriodicalExecuter(yourFunction, 3);
And when you want it to stop, tell it to stop (assuming it has been started):
if (thePE) {
thePE.stop();
thePE = undefined;
}
(PeriodicalExecuter#stop docs here.)