I am relatively new to CodeIgniter, so I'm not sure if this is just bad coding, or if it is a problem with how I'm using CodeIgniter's flash data. For context: the user submits a phrase in a simple HTML form. The phrase is compared against what should be typed in (pretty simple, right?). This correct phrase changes based upon what step in the activity they are on. When they get the text wrong, I am attempting to use flashdata to show the error message. Here are the controller portions, followed by the view:
//Get step number
$step = $this->input->post('step');
$correct_text = array(
1 => 'TESTPHRASE',...
...
//If user enters the correct text
$entered_text = strtoupper($this->input->post('entered_text'));
if ($entered_text == $correct_text[$step])
{
...
}
//If user enters the incorrect text
else
{
$data['step'] = $step;
$this->session->set_flashdata('entry_error', '<b>Sorry!</b>Your entry was incorrect. Be sure to carefully read the instructions!');
$this->load->view('template', $data);
}
Here is the view that only runs every other time.
<?php
if ($this->session->flashdata('entry_error'))
{ ?>
<div id="game_error">
<?php echo $this->session->flashdata('entry_error'); ?>
</div>
<?php } ?>
From the docs: CodeIgniter supports "flashdata", or session data that will only be available for the next server request, and are then automatically cleared.
You are setting the flashdata and then trying to access it during the same request. It's not available until the next request which is why it seems like it's only working every other time.
Related
I'm attempting to validate a users login attempt and inform them that
Their username is wrong or
their password is wrong (because I personally hate with a blind fury when a website doesn't inform me WHICH it is but that's beside the point).
I've read a lot of SO posts on this issue but the ones I've found are years old and I'm dealing with CodeIgniter 3.0.1.
This is the code that I have in place. I'm using Eclipse PDT to as my IDE and I like it quite a bit (but that's getting off track) so I've been able to step through the execution and watch as it just fails completely.
IF (!$this->User->login( //Testing shows this works fine - the SWITCH statement gets executed as it should and the BADUSERNAME case is followed through.
addslashes(strtolower($this->input->post('username', TRUE))),
addslashes($this->input->post('password', TRUE)),
$this->getIP())){
SWITCH($this->User->ID){
CASE 'BADUSERNAME':
$this->session->set_flashdata('user_msg', 'Invalid Username');
BREAK;
CASE 'BADPASSWORD':
$this->session->set_flashdata('user_msg', 'Invalid Password');
BREAK;
CASE 'ALREADYLOGGEDIN':
$this->session->set_flashdata('user_msg', 'You are logged in elsewhere.');
BREAK;
DEFAULT:
$this->session->set_flashdata('user_msg', 'Something has gone terribly wrong. Please try logging in again.');
BREAK;
}
redirect(base_url());
}
Then a bit further down I load the header, body, and footer views - The body is where the error message should be displayed but it's not..
<div id="contentarea">
<div class="container">
<?PHP
ECHO $this->session->flashdata('show_validation') ? validation_errors() : '';
$error = $this->session->flashdata('user_msg'); //This is where it's supposed to get it...
IF ($error) //And this is where it's supposed to show it...
ECHO "<div class='error'>$error</div>";
?> //But the value is wiped so it only ever grabs NULL.
I've followed the path of execution after calling the redirect after setting the flash data and I've noticed that after the redirect finishes it's chain of execution, it calls exit;.
Then everything loads again from the index.php file, and when Session finally pops up... the value 'user_msg' is nowhere to be found.
So clearly I'm doing something wrong here - what am I doing wrong here? Will the flash_data only persist until that redirect is called? Even the session_data values (calling $this->session->value = 'some arbitrary user message' fails to persist).
How can I persist the message for the next time the body element is loaded so that it can tell the user "Hey, didn't find you" or "Hey, your password wasn't right"?
EDIT 1
So it turns out I do not need to redirect for what I am doing as POSTing (submitting the user name and password) handles that for me.
I'm going to leave the question here for anyone else who may need it answered though - perhaps the answer is simply that Flash data just doesn't survive a redirect?
Flashed data is only available for the next http request, if you reload the page a second time, data is gone.
To persist data in the session, you want to set the variable in the session.
Codeigniter
Adding Session Data
Let’s say a particular user logs into your site. Once authenticated, you could add their username and e-mail address to the session, making that data globally available to you without having to run a database query when you need it.
You can simply assign data to the $_SESSION array, as with any other variable. Or as a property of $this->session.
Alternatively, the old method of assigning it as “userdata” is also available. That however passing an array containing your new data to the set_userdata() method:
$this->session->set_userdata($array);
$this->session->set_userdata('username', 'username is wrong');
in the view
$this -> session ->userdata('username');
or
$this ->session -> username;
Reference Session Library Codeigniter.
hope this help.
All you have to do is use $this->session->keep_flashdata('user_msg') with $this->session->unset_userdata('user_msg')
here is the solution (view file)
<?php
$error = $this->session->flashdata('user_msg');
if (isset($error)) {
echo '<div class="error">' . $error . '</div>';
$this->session->unset_userdata('user_msg');
}
?>
After that in your controller construct function (In that controller where you redirecting)
public function __construct() {
parent::__construct();
//.....
$this->session->keep_flashdata('user_msg');
}
I had same problem and this works. do not forget to clear cache when try or try in different browser
You can use codeigniter's flashdata to display errors separately.
This is what I usually use.
Controller:
$errors = array();
foreach ($this->input->post() as $key => $value){
$errors[$key] = form_error($key);
};
$response['errors'] = array_filter($errors);
$this->session->set_flashdata($response['errors']);
redirect('your-page', 'refresh');
And the to display the errors use
<?php echo $this->session->flashdata('field_name'); ?>
Since I asked my question (Previous question) in a way no doubt most users think "dude this is tl;dr" let me put it more simple. I want to use post-redirect-get pattern to avoid user refreshing the site and resubmiting the data etc... I understand that in order to do so I have to redirect the user from html form, through php processing script and back to a new site (or original html form site) that displays the processed data.
Now my question. How do I GET my processed data back from my php? I don't understand the GET part... Currently I don't know how to show php generated data in a nice html display (view) page without include 'site.html';. This example isn't what I am looking for either: Simple Post-Redirect-Get code example. Code in the below example just redirects me to a current page.
It depends on context, but for example:
Given: invoice-form.html, invoice-processing.php and current-invoices.php:
User fills in data on invoice-form
User submits form which has action="invoice-processing.php"
Browser POSTs data to invoice-processing
invoice-processing takes the data from the form and puts it in a database
invoice-processing outputs 302 status and a Location header
Browser goes to current-invoices
current-invoices fetches a list of invoices (including the most recently submitted one) from the database and sends them to the browser as an HTML document
I hope this will help because it has taken me quite a while to get it as well. I tested my understanding like this. I have two php pages, the first page (prg1.php) sends the form to the database, action set to the second one (prg2.php). prg2.php checks the POST data, updates the database and issues a redirect to prg1.php with anything I need to pass back as GET variables. prg2.php looks like this
<?php
if (isset($_POST['gameid'])){
// process the data, update the database
$gameid = htmlspecialchars($_POST['gameid']);
$playerid = htmlspecialchars($_POST['playerid']);
$message = htmlspecialchars($_POST['message']);
//redirect, after updating the database
$getinfo = '?gameid=' . $gameid . '&playerid=' . $playerid;
header("Location: prg1.php" . $getinfo );
exit();
}
?>
You could try something like this:
/****************************************/
/* Fetch my data. */
/****************************************/
$mydata = $_GET["data"];
/****************************************/
/* Has to be sent before anything else! */
/****************************************/
header( 'Location: http://www.yoursite.com/index.php?data='.$mydata );
Sorry if I'm duplicating threads here, but I wasn't able to find an answer to this anywhere else on StackOverflow.
Basically what I'm trying to do is make a list in which variables entered in a form by a user can be kept. At the moment, I have the code which makes this possible, and functional, however the variables entered in the form only appear on the list after the user hits submit... As soon as I refresh the page or go to the page from somewhere else, the variables disappear. Is there any way I can stop this from happening?
Edit: here are the codes:
//Page 1
<?php
session_start();
$entries = array(
0 => $_POST['signup_username'],
1 => $_POST['signup_email'],
2 => $_POST['signup_city']);
$entries_unique = array_unique($entries);
$entries_unique_values = array_values($entries_unique);
echo "<a href='Page 2'>Link</a>";
$_SESSION['entries_unique_values'] = $entries_unique_values;
?>
//Page2
<?php
session_start();
$entries_unique_values = $_SESSION['entries_unique_values'];
foreach($entries_unique_values as $key => $value) {
$ValueReplace = $value;
echo "<br /><a href='http://example.com/members/?s=$ValueReplace'>" . $value . "</a><br/>";
}
?>
Your question is really quite vague. the answer depends on how much data you have to store, and fopr how long you need it to exsist.
By variable I assume you mean data the user has entered and that you want to put into a variable.
I also presume that the list of variables is created by php when the form is submitted.
Php will only create the variable list when the form is submitted as php is done entirely on the server, therefore you will not have or see the variables until the form is submitted.
if you wanted to be able to see the list as it is being created you could use javascript then once you have you php variables the javascript list isn't necesary.
each time you request a php page wheather it is the same one or not the server generates a totally new page, meaning all unhardcoded variables from previous pages will be lost unless you continually post the variables around the pages the server will have no memory of them.
You have a few viable options.
) keep passing the user created variables in POST or GET requests so each page has the necesary info to work with. Depending on the situation it might or might not be a good idea. If the data only needs to exsits for one or two pages then it is ok, but bad if you need the data to be accessable from any page on your web.
2.) start a session and store the variables in a session. Good if the data only needs to be around while the user is connected to the site. but will be lost if user close window or after a time.
3.) place a cookie. not a good idea but ok for simple data.
4.) create a mysql database and drop the variable info in there. great for permanent data. this is how i always complex user data.
just a few ideas for you to look into as it is difficult to see what you really mean. good luck.
use PHP session or store variable values in Cookies via JS or using PHP. It would be nice if you show your working codes :)
Your idea is fine, however you just need to add a little condition to your Page 1 that only set your SESSION values when POST is made, that way it will keep the values even if you refresh. Otherwise when you visit the page without a POST those values will be overwritten by blank values, which is what you are seeing now. You can modify it like
<?php
session_start();
if(isset($_POST["signup_username"]))
{
$entries = array(
0 => $_POST['signup_username'],
1 => $_POST['signup_email'],
2 => $_POST['signup_city']);
$entries_unique = array_unique($entries);
$entries_unique_values = array_values($entries_unique);
$_SESSION['entries_unique_values'] = $entries_unique_values;
}
echo "<a href='http://localhost/Calculator/form2.1.php'>Link</a>";
?>
You could use JavaScript and HTML5 local storage.
My website relies completely on a random page generator that loads a page from a text file list. The code was kindly written by "lserni" on the forum. The script has been working perfectly the last few days, and it's happily processed over 100,000 page views in 3 days!
I noticed today however that it seems to have stopped working properly. If you are a brand new visitor to the page, or you've cleared your internet cache/cookies etc - When you load the page for the first time, it doesn't randomly generate a page.. it just shows a BLANK page. If you then refresh the page, the script works perfectly. I just can't get my head round it, but it's now resulted in a large drop in traffic! Hope you can help:
<?php
session_start();
if (!isset($_SESSION['urlist'])) // Do we know the user?
$_SESSION['urlist'] = array(); // No, start with empty list
if (empty($_SESSION['urlist'])) // Is the list empty?
{
$_SESSION['urlist'] = file("linklist.txt"); // Fill it.
$safe = array_pop($_SESSION['urlist']);
shuffle($_SESSION['urlist']); // Shuffle the list
array_push($_SESSION['urlist'], $safe);
}
$url = trim(array_pop($_SESSION['urlist']));
header("Location: $url");
?>
It's actually the LAST item in the file that's used first if there is no session data.
{
$safe = array_pop($_SESSION['urlist']); // gets item at the END of the array
shuffle($_SESSION['urlist']);
array_push($_SESSION['urlist'], $safe); // puts item at the END of the array
}
$url = trim(array_pop($_SESSION['urlist']));// gets item at the END of the array
So if you introduced a newline in your textfile at the end, it may be your issue.
I would suggest, after the header call, add some HTML that explains where the user is being redirected to. All being well nobody will ever see it, but it could help diagnose why the user gets an empty page.
Ever stumbled on a tutorial that you feel is of great value but not quite explained properly? That's my dilemma. I know THIS TUTORIAL has some value but I just can't get it.
Where do you call each function?
Which function should be called
first and which next, and which
third?
Will all functions be called in all files in an application?
Does anyone know of a better way cure the "Back Button Blues"?
I'm wondering if this will stir some good conversation that includes the author of the article. The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed. Basically, you want to control the back button by calling the following three functions during the execution of the scripts in your application. In what order exactly to call the functions (see questions above) is not clear from the tutorial.
All forwards movement is performed by
using my scriptNext function. This is
called within the current script in
order to activate the new script.
function scriptNext($script_id)
// proceed forwards to a new script
{
if (empty($script_id)) {
trigger_error("script id is not defined", E_USER_ERROR);
} // if
// get list of screens used in this session
$page_stack = $_SESSION['page_stack'];
if (in_array($script_id, $page_stack)) {
// remove this item and any following items from the stack array
do {
$last = array_pop($page_stack);
} while ($last != $script_id);
} // if
// add next script to end of array and update session data
$page_stack[] = $script_id;
$_SESSION['page_stack'] = $page_stack;
// now pass control to the designated script
$location = 'http://' .$_SERVER['HTTP_HOST'] .$script_id;
header('Location: ' .$location);
exit;
} // scriptNext
When any script has finished its
processing it terminates by calling my
scriptPrevious function. This will
drop the current script from the end
of the stack array and reactivate the
previous script in the array.
function scriptPrevious()
// go back to the previous script (as defined in PAGE_STACK)
{
// get id of current script
$script_id = $_SERVER['PHP_SELF'];
// get list of screens used in this session
$page_stack = $_SESSION['page_stack'];
if (in_array($script_id, $page_stack)) {
// remove this item and any following items from the stack array
do {
$last = array_pop($page_stack);
} while ($last != $script_id);
// update session data
$_SESSION['page_stack'] = $page_stack;
} // if
if (count($page_stack) > 0) {
$previous = array_pop($page_stack);
// reactivate previous script
$location = 'http://' .$_SERVER['HTTP_HOST'] .$previous;
} else {
// no previous scripts, so terminate session
session_unset();
session_destroy();
// revert to default start page
$location = 'http://' .$_SERVER['HTTP_HOST'] .'/index.php';
} // if
header('Location: ' .$location);
exit;
} // scriptPrevious
Whenever a script is activated, which
can be either through the scriptNext
or scriptPrevious functions, or
because of the BACK button in the
browser, it will call the following
function to verify that it is the
current script according to the
contents of the program stack and take
appropriate action if it is not.
function initSession()
// initialise session data
{
// get program stack
if (isset($_SESSION['page_stack'])) {
// use existing stack
$page_stack = $_SESSION['page_stack'];
} else {
// create new stack which starts with current script
$page_stack[] = $_SERVER['PHP_SELF'];
$_SESSION['page_stack'] = $page_stack;
} // if
// check that this script is at the end of the current stack
$actual = $_SERVER['PHP_SELF'];
$expected = $page_stack[count($page_stack)-1];
if ($expected != $actual) {
if (in_array($actual, $page_stack)) {// script is within current stack, so remove anything which follows
while ($page_stack[count($page_stack)-1] != $actual ) {
$null = array_pop($page_stack);
} // while
$_SESSION['page_stack'] = $page_stack;
} // if
// set script id to last entry in program stack
$actual = $page_stack[count($page_stack)-1];
$location = 'http://' .$_SERVER['HTTP_HOST'] .$actual;
header('Location: ' .$location);
exit;
} // if
... // continue processing
} // initSession
The action taken depends on whether
the current script exists within the
program stack or not. There are three
possibilities:
The current script is not in the $page_stack array, in which case it is
not allowed to continue. Instead it is
replaced by the script which is at the
end of the array.
The current script is in the
$page_stack array, but it is not the
last entry. In this case all
following entries in the array are
removed.
The current script is the last entry
in the $page_stack array. This is
the expected situation. Drinks all
round!
That is a good discussion but more to the point you should be looking into Post Redirect Get (PRG) also known as "Get after Post."
http://www.theserverside.com/patterns/thread.tss?thread_id=20936
If you do not understand my article then you should take a close look at figure 1 which depicts a typical scenario where a user passes through a series of screens – logon, menu, list, search, add and update. When I describe a movement of FORWARDS I mean that the current screen is suspended while a new screen is activated. This happens when the user presses a link in the current screen. When I describe a movement as BACKWARDS I mean that the user terminates the current screen (by pressing the QUIT or SUBMIT button) and returns to the previous screen, which resumes processing from where it left off. This may include incorporating any changes made in the screen which has just been terminated.
This is where maintaining a page stack which is independent of the browser history is crucial – the page stack is maintained by the application and is used to verify all requests. These may be valid as far as the browser is concerned, but may be identified by the application as invalid and dealt with accordingly.
The page stack is maintained by two functions:
scriptNext() is used to process a
FORWARDS movement, which adds a new
entry at the end of the stack and
activates the new entry.
scriptPrevious() is used to process
a BACKWARDS movement, which removes
the last entry from the stack and
re-activates the previous entry.
Now take the situation in the example where the user has navigated to page 4 of the LIST screen, gone into the ADD screen, then returned to page 5 of the LIST screen. The last action in the ADD screen was to press the SUBMIT button which used the POST method to send details to the server which were added to the database, after which it terminated automatically and returned to the LIST screen.
If you therefore press the BACK button while in page 5 of the LIST screen the browser history will generate a request for the last action on the ADD screen, which was a POST. This is a valid request as far as the browser is concerned, but is not as far as the application is concerned. How can the application decide that the request is invalid? By checking with its page stack. When the ADD screen was terminated its entry was deleted from the page stack, therefore any request for a screen which is not in the page stack can always be treated as invalid. In this case the invalid request can be redirected to the last entry in the stack.
The answers to your questions should therefore be obvious:
Q: Where do you call each function?
A: You call the scriptNext()
function when the user chooses to
navigate forwards to a new screen,
and call the scriptPrevious()
function when the user terminates
the current screen.
Q: Which function should be called
first and which next, and which
third?
A: Each function is called in
response to an action chosen by the
user, so only one function is used
at a time.
Q: Will all functions be called in
all files in an application?
A: All functions should be available
in all files in an application, but
only called when chosen by the user.
It you wish to see these ideas in action then you can download my sample application.
The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed.
Your premise is wrong. There is no such thing as "Back Button Blues", if you design your application as a web application. If you design your application without any server side state, you will never run into this problem in the first case. This minimalistic approach to web applications works remarkably well, and is usually known as REST.
# troelskn
If you design your application without any server side state ....
It is not possible to design an effective application which does not have state, otherwise all you have is a collection of individual pages which do not communicate with each other. As maintaining state on the client is fraught with issues there is no effective alternative but to maintain state on the server.
#Marston.
I solved the problem with post/redirect/get but I believe the tutorial has some merit and perhaps Tony Marston can elaborate on it. And how it could be used to solve not necessarily my particular problem but perhaps something similar. Or how is it better than post/redirect/get if the functions can in fact be used in solving my particular problem. I think this will be a good addition to the community here.
if ($_POST) {
process_input($_POST);
header("Location: $_SERVER[HTTP_REFERER]");
exit;
}