So the chain of events is:
The user submits a form.
During the processing of the submission, there is a message generated, such as "Your record was saved."
The user is redirected to a new page, say the search results.
The new page needs to display the message.
So, the question is how to get the message from step 2 to step 3? This is only one simple example...there are many other much more complicated examples.
I am using PHP.
Needs:
supports multiple messages and need to be formatted on the receiving machine as required
messages can be added on the same page (such as within step 4)
messages added from inside any function or object
Some options I have come up with:
store in a session variable as an array and emptied after each display
pass as a get or query parameter; can get annoying as you are constantly processing this and have to remember to get it; as it can get long, it could easily go over the max length of the query string
store in the database on a per session basis (may not always be for a logged in user); this would require an extra insert on each page where they are added, possibly multiple, and an extra select on every page
Currently I have been storing the messages in the session in an array, but I'm wondering if there is a better way. I don't think the other 2 options above are very good.
Edit: I use 2 functions for the session method: AddStatusMsg() (adds an element to the array) and DisplayStatusMsg() (returns an HTML formatted message and empties the array).
I would recommend AGAINST storing these messages either in the database or in the session, for one simple reason: tabs. (Well, really, the stateless nature of HTTP.)
Think of a person who's got multiple tabs open of different sections of your website. This person performs some action and while that loads, switches to another tab and clicks on a link. If you're storing the messages in the session/database and the switched-to tab is a page that can display these messages too, the user has now entered a race condition where depending on which request the server responds to first, the messages may display where they were not intended.
Now, there are some situations where this legitimately might not matter, but it could also be extremely confusing in some cases.
Putting the messages in the request doesn't have to be as bad as it initially seems. Perhaps you could store all the messages you want to display in the database with a numeric (or, for bonus obfuscation, hash) ID, and pass a list of IDs in the query string. This keeps the query string short, and all you have to do is keep track of what ID corresponds to what message in your code.
I would stick with the session approach only perhaps adding support for this messaging system on the master page. You are on the right way as the all other approaches have a greater cost, of simplicity or performance.
I suppose you have a master page which is the template for all other pages. If you don't have it's a good reason to have one, so you don't need to take care of handling the displaying of the messages on every page you need it as long as you have a specific place to show them.
You can also use a specific div rendered by the master page for that and let the position be handled by the current page. If I understand correctly you need some kind of timing between the showing of the message and the user redirection to another page. This could be achieved using any AJAX library to show that div I said before and then redirecting to a new page.
I suggest taking a look into jQuery.
This is how I like to do it:
function set_message($message_type, $message)
{
$_SESSION['messages'][$message_type][] = $message
}
function get_messages()
{
$messages_array = $_SESSION['messages'];
unset($_SESSION['messages']);
return $messages_array;
}
where $message_type can be "warning", "error", "success", etc. and depending on the type you can show the user a different image/color/whatever.
This problem is a classic example of how to have data persist in a "stateless protocol" like http.
Your options are:
Pass it in the GET parameters (not
user friendly)
Store it in the DB
Store it in Session
Options 2) and 3) require the user to have a cookie (otherwise, there's no way to match the user to the message). Between them, I'd go with PHP's built in sessions. Simply set a session variable at your step 2, and have the search page always check for the variable in your step 4
Nothing to it. Don't over complicate things.
Probably the best way is to store it in the session. It's the simplest way and as John said, 'Don't over complicate things'.
Store it in the database as well as the session. This way the user can get to his history if he needs it, and you have easy access through the session data.
Don't use a query parameter, it'll only confuse the user at some point when the message is displayed when it shouldn't be.
Displaying the messages should be a part of your main template (in other words; done once).
Maybe a slight improvement would be to store, instead of an array, an object's instance that gets populated and knows how to display the messages appropriately, deleting the data itself after any display routine gets called. That way you don't have to repeat the display and delete logic everywhere, plus, you can code different output routines in the object depending on the need.
I think you're doing it the right way. You should stay away from the database for this and putting it in the URL is ugly. You could write a nice little class for this which can make it simpler.
Here's a little session class:
<?php class session
{
public function __construct()
{
session_start();
}
public function set($name, $value)
{
$_SESSION[$name] = $value;
}
public function get($name)
{
return (isset($_SESSION[$name])) ? $_SESSION[$name] : false ;
}
public function delete($name)
{
unset($_SESSION[$name]);
}
public function destroy()
{
$_SESSION = array();
#session_destory();
#session_regenerate_id();
}
}
A little message class can be built on that pretty easily.
I'm at this crossroad myself and I've considered all options extensively.
How about storing two browser
cookies, one called page and the
other called message.
On redirect you overwrite the cookie.
When the page loads you check if
said cookie exists (in the http
headers sent by the client).
Check if it's for that page, if it
is, store the message in a variable
and unset the cookies.
If it's not for that page, ignore
it, it will be output on the other
tab that is loading or if it is for
a page that for some reason never
unset the cookie it will eventually
expire.
This avoids using the database and session cookies.
Related
So I am aware of these two common ways of passing variables across php pages.
1. PHP SESSIONS
I understand that $_SESSION is a php global variable that can hold variables across php pages during the session of the browser.
It works well but my concern with it is if a user for what ever reasons, decides to type the url of a page or goes into their history and accesses a url page for the website, the $_SESSION variable may not be set, if it was expecting the user to get to this page from a set route/path.
In addition, if a user goes into another page, and the page sets an already defined $_SESSION to another value, and then decides to go back to the previous page, the $_SESSION variable is not correct for that page, causing many errors.
2. URL passing
This is by far the most reliable in my opinion. The only concern I have with this, is the pages can get rather messy with long URL's.
page1.php?postId={variable goes here}
passing 4,5 or 6 variables can get a bit messy, I also need to encode then or encrypt them. The URL can get rather long, and I am not sure how I feel about passing variables across the URL.
My Question:
What is the best way to pass variables from one php page to another. Are the two methods above the best way to go about it, or is there another my efficient way. Also if efficiency isn't the issue, then what is the most secure procedure/method.
Thanks for your time.
This is largely going to depend what you're trying to do? $_SESSION variables and $_GET variables largely have different purposes in web programming (although, yes, you could force some sway between the two).
The question you need to ask yourself is "is the variable storing information on the user OR directing the webserver to do something" if it's the former then use $_SESSION if it's the latter then $_GET.
You wouldn't for example want to pass loggedon=true as a GET variable (ignoring the security implications) because you would have to update every single link on the page to have the query string appended to it which, as you say, would lead to some untidy URLs.
SESSION
Is most commonly used for storing information about a user. Some examples:
Log on status
Shopping basket
Session preferences
For example when a user is successfully logged on you will want some way to remember that between page loads:
session_start();
$_SESSION["loggedon"] = true;
In every subsequent page request you can then check:
session_start();
if(!$_SESSION["loggedon"] ?? null){
echo "ERROR: You shouldn't be here!";
exit;
}
Note that $_SESSION is only accessible to the server, can't be directly accessed by the website user, and is persistent until the session closes.
GET
On the other hand is sent with every request and is typically used when you want to pass non-sensitive information from the user to the webserver. Some examples:
Language preferences
User input (e.g. a search query when using a search engine)
Forgotten password secure codes
Suppose you have a cookery website and 1000 recipes. You would likely only have one page to show the recipe and pass a GET variable in the URL to indicate which recipe should be loaded
http://www.mycookingwebsite.com/recipe.php?recipeid=477
Note that GET requests are visible to the user, can be modified, and show up in history etc. as well.
N.B. Do not pass sensitive details (e.g. username/password) over GET - not least because they would show up in the browser history!
You mention passing variables from one page to another. But I'm not quite clear on whether you mean Server->Server (SESSION) OR Client->Server(GET)?
An example of this all coming together would be in the case of a shopping cart:
At the back end you have an array stored in your session with the items in the cart, this is persistent throughout the session. On the client side you have the ability to send a GET (most people would probably POST) request to tell the server about the new product you want to add to the list.
If your primary concern is that users may find themselves at the wrong "stage" then I suggest building in some checks to make sure that they are in the right place at the right time.
For example given a quiz with 10 questions... If the user clicks a link which drops them at question 5 you check to see if they've already answered questions 1-4 and then act appropriately depending on the answer.
Usually, AJAX is used for dynamically modifying web pages by asynchronously communicating with the backend (in my case, CodeIgniter) to avoid page reloading.
However, I am thinking about using session data to do the same for those cases where page reloading is not an issue.
Here is a code snippet of what I am trying to do:
if($this->Member_model->checkPassword($data)){ //checks whether old password is correct
$this->Member_model->setPassword($new_pass); //sets the new password
$this->session->set_userdata('pass_meta', 'success'); //stores success in session data
}
else {
$this->session->set_userdata('pass_meta', 'fail'); //stores fail in session data
}
redirect('profile','refresh'); //refreshes the page
And while building the profile page, this is what I am doing:
if($this->session->userdata('pass_meta')){ //checks whether the field pass_meta is set in the session
$data['pass_meta'] = $this->session->userdata('pass_meta'); //reads the field into $data (which will be passed to the page)
$this->session->unset_userdata('pass_meta'); //unsets the field in the session
}
else {
$data['pass_meta'] = "";
}
So the success/failure message gets passed to the View which triggers the appropriate message.
Now, this method is working perfectly for me. My question is: is doing this a good idea? What may be the pros/cons of this design approach?
Most frameworks implement something called flash messages, which are messages stored in session for one request only. This prevents issues with messages persisting when they should not. There is nothing wrong in using session like that, the main consideration is not to swamp session with too much data (especially if you're using server space to store sessions).
EDIT: Usually you just pass the whole message/translation key to the session storage, and then display it in your views with proper class. That way you can use generic warning/success messages in different view with no need for additional logic for each one.
In my days of writing web applications, I'm missing a simple way for a PHP script to direct to another PHP script while passing along data without using the URL
Browsers can pass data invisibly to a PHP script using the $_POST array. So I'm devising a script that will dump the contents of $_SESSION["POST"] into the $_POST array to mimic the passing of post data, then clears $_SESSION["POST"].
For instance, a page X contains a login form. Page X directs to page Y to validate the data. Page Y discovers that the login information is incorrect, and redirects back to page X - which now displays the error message "Login information incorrect" from $_POST.
Am I crazy for missing this feature? Is there some other method of doing this easily that I'm missing?
Please respond with anything that can be helpful.
You could use the session. On page X, you'd put the data into the session. On page Y, you'd validate the data and handle the redirect. You can put your error message into the session too.
The session persists between requests, so it's the perfect place to store that kind of data.
EDIT
OK, I'd do things with session variables, but if you want to avoid that you do have a few other options I can think of besides posting:
You can use files on the server (such as temporary files). Use the user's session key to identify which file is theirs, and you can read and write whatever data you care to it.
You can put the data in a database. That would work too.
Of course neither of those is a true post. If you want a true post, you have another two options.
First, you can return the data to the page in a hidden form, and use JavaScript to trigger a POST. This is simple to do, but it requires the data to pass through the browser. This means you'd have to take care that a user didn't change the data, and the user would have to have JavaScript on. You can checksum the data to ensure it isn't modified, but the JavaScript problem is unsolvable.
Another way to do it would be to take the user out of the equation entirely. When the user submits to page A, page A could make a POST to page B, check the response, and then redirect the user to the proper place. This would be just like if you had to make a JSON or SOAP call to a 3rd party service, except you control that service. It's been a little while, but I believe that HttpRequest is the class to use to do this.
It would be ideal if that URL you check with returns a simple answer ("true", "false", "yes", "no", "good", "bad", whatever), but as long as you can tell by the response whether they were successful or not, you can do it.
Now I should note that I'd agree with mvds, this sounds like a function that should be included in page A so that it can do all the work but the code can be shared with other pages. Having page A post to page B and then redirect to A or C seems unnecessarily complex. Page A can easily accomplish all this. I read your comment on his answer, but it seems there should be another way to accomplish this.
Abstract the performed actions to functions and/or classes, and the need for such kludges will vanish. Concrete: both page X and Y could call the same function to validate the posted login data.
Page X redirecting to page Y to do validation means handing back control to the client, while you could (and should) validate the data right away.
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.)
I have an application that supplies long list of parameters to a web page, so I have to use POST instead of GET. The problem is that when page gets displayed and user clicks the Back button, Firefox shows up a warning:
To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.
Since application is built in such way that going Back is a quite common operation, this is really annoying to end users.
Basically, I would like to do it the way this page does:
http://www.pikanya.net/testcache/
Enter something, submit, and click Back button. No warning, it just goes back.
Googling I found out that this might be a bug in Firefox 3, but I'd like to somehow get this behavior even after they "fix" it.
I guess it could be doable with some HTTP headers, but which exactly?
See my golden rule of web programming here:
Stop data inserting into a database twice
It says: “Never ever respond with a body to a POST-request. Always do the work, and then respond with a Location: header to redirect to the updated page so that browser requests it with GET”
If browser ever asks user about re-POST, your web app is broken. User should not ever see this question.
One way round it is to redirect the POST to a page which redirects to a GET - see Post/Redirect/Get on wikipedia.
Say your POST is 4K of form data. Presumably your server does something with that data rather than just displaying it once and throwing it away, such as saving it in a database. Keep doing that, or if it's a huge search form create a temporary copy of it in a database that gets purged after a few days or on a LRU basis when a space limit is used. Now create a representation of the data which can be accessed using GET. If it's temporary, generate an ID for it and use that as the URL; if it's a permanent set of data it probably has an ID or something that can be used for the URL. At the worst case, an algorithm like tiny url uses can collapse a big URL to a much smaller one. Redirect the POST to GET the representation of the data.
As a historical note, this technique was established practice in 1995.
One way to avoid that warning/behavior is to do the POST via AJAX, then send the user to another page (or not) separately.
I have been using the Session variable to help in this situation. Here's the method I use that has been working great for me for years:
//If there's something in the POST, move it to the session and then redirect right back to where we are
if ($_POST) {
$_SESSION['POST']=$_POST;
redirect($_SERVER["REQUEST_URI"]);
}
//If there's something in the SESSION POST, move it back to the POST and clear the SESSION POST
if ($_SESSION['POST']) {
$_POST=$_SESSION['POST'];
unset($_SESSION['POST']);
}
Technically you don't even need to put it back into a variable called $_POST. But it helps me in keeping track of what data has come from where.
I have an application that supplies long list of parameters to a web page, so I have to use POST instead of GET. The problem is that when page gets displayed and user clicks the Back button, Firefox shows up a warning:
Your reasoning is wrong. If the request is without side effects, it should be GET. If it has side effects, it should be POST. The choice should not be based on the number of parameters you need to pass.
As another solution you may stop to use redirecting at all.
You may process and render the processing result at once with no POST confirmation alert. You should just manipulate the browser history object:
history.replaceState("", "", "/the/result/page")
See full or short answers