PHP OOP message keeps displaying on page refresh - php

I have a relatively simple class which deletes a post:
function delete_post($postid, $reason){
//Stuff to delete post
$this->delete_response = 'Thanks, your course has been removed.';
}
This function is called at the top of a page with a form on. If the form is submitted, the same page checks the POST[] and carries out the function, like so:
if(!empty($_POST['removecourse'])){
$courseManager->delete_post($_POST['courseid'], $_POST['cancel-reason']);
echo $courseManager->delete_response;
};
So my problem is... when I refresh the page, the message keeps displaying. I know this is because I am re-submitting the form, and because there is no such P/R/G pattern going on, but as i am new to OOP, im wondering if im doing this the right way, or if anyone could suggest a way similar to PRG or something?

Add an if that test if somthing changed, like mysql_affected_rows
function delete_post($postid, $reason)
{
//Stuff to delete post
if(mysql_affected_rows())
{
$this->delete_response = 'Thanks, your course has been removed.';
}
}

Related

Error in executing tempdata

Form.php(controller)
public function dispdata()
{
$result['data']=$this->Form_model->displayrecords();
$this->load->view('display_records',$result);
if (!$this->session->userdata('ci_session'))
{
redirect('Form/login');
}
else
{
$this->session->set_tempdata('item',$result,5);
}
}
display_records(view)
<?php
if($this->session->tempdata('item')){
redirect('Form/login');
}
?>
im trying to work with the tempdata concept. i have a registration form where i have stored all the registered details in the datbase and those store details of database i have displayed
it in the view page.
how that i have displayed all the database details in a view page that view page im trying to display only for 5sec and after 5sec it should redirect to the login page. i have tried with the above code but its not working please can anyone tel me where im going wrong ?
The tempdata feature for sessions only affects how long the data is allowed to be stored. The removal of the data, after 5 seconds in your case, won't cause anything else to change on the page.
As far as I can tell you don't need tempdata at all. Try this to see if you get the behavior you want.
public function dispdata()
{
if (!$this->session->userdata('ci_session'))
{
redirect('Form/login');
}
$result['data']=$this->Form_model->displayrecords();
$this->load->view('display_records',$result);
// sleep for 5 seconds
sleep(5);
redirect('Form/login');
}
Why did I remove the else from your code? Because redirect does not return - it ends script execution. So, when the if evaluates to true and the redirect executes this script is done.

How can I persist data for a redirect with CodeIgniter?

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'); ?>

Page reloading before it know the post has been deleted?

I have a class that contains 2 functions one for removing post and one for submitting post. The function for submitting the post will redirect to any page I want just fine and if it is the same page it will be displayed with the new post.
The function used for removing the post will refresh or redirect but if it's redirected back to the same page the page does not appear updated until the page is refreshed again (a second time). I have looked and haven't found anything that works or a reason why this is happening. I'm new to php so go easy on me!
Is the page reloading before it know the post has been deleted? What can I do to solve this?
Here is my code:
class userPost{
// For Removing Post
function remove(){
if(($_SERVER['REQUEST_METHOD'] == "POST") && ($_POST['delete_id'])){
if(!$_POST['delete_id'] || !$_SESSION['SESS_USER']){
header('Location: ?id=profile');
}
else{
$delete = mysql_real_escape_string($_POST['delete_id']);
$remove = mysql_query("DELETE FROM Post WHERE post_id = '".$delete."' AND post_member='" . $_SESSION['SESS_USER'] . "'");
if($remove){
header('Location: ?id=profile');
}
elseif(!$remove){ ?>
<script>
$('#div-id').triggerevent(function(){
$('#div-id').html(newContent);
});
</script>
<?php
} // End Else
} // End Else
} // End If
} // End If
} // End Class
You need an exit; after header. Otherwise PHP continues to process the script.
As an aside: Don't continue programming this way. There are so many issues with this script I wouldn't know where to start. A good book to learn PHP the right way is PHP : Ojects, Patterns, and Practices by Matt Zandstra.

Organizing a PHP page with a bunch of $_POST's

I am making quite a large online points/purchasing system in PHP and just have a fundamental question.
All the relevant stuff is on a single PHP page within the site, with "includes" from other parts of the site such as shopping cart, points review, products etc..., but throughout the page there are stages where the user clicks a form submit button to pass values via $_POST.
As there is a main page for all this stuff, I have a part at the top of the page where it takes all the POST values and makes decisions based upon them, like so:
if($_POST['add']) {
$product_id = $_POST['add'];
}
if($_POST['remove']) {
$rid = $_POST['id'];
$cart->del_item($rid);
}
if($_POST['empty']){
$cart->empty_cart();
}
if($_POST['purchase']) {
foreach($cart->get_contents() as $item) {
$sql="INSERT INTO wp_scloyalty_orders VALUES (".$user_id.", ".$item['id'].")";
$result=mysql_query($sql);
}
$cart->empty_cart();
unset($_SESSION['cart']);
}
if($_POST['add']) {
query_posts('post_type=prizes&showposts=-1&p='.$product_id.'');
while (have_posts()) : the_post();
$my_meta = get_post_meta($post->ID,'_my_meta',TRUE);
if($calctotalnew > $my_meta['pointsvalue']){
$cart->add_item(get_the_id(), 1, $my_meta['pointsvalue'], get_the_title());
} else {
echo 'You do not have sufficient points to redeem this product...';
}
endwhile;
wp_reset_query();
}
So my question is... is this really a good way to organize a system, having the form actions go to the same page that the form is on, and have a load of IF statements to decide what to do with the POST values?
Thanks! :)
it's generally best to capture separate POST calls (grouped by type) in separate actions. I usually go as follows:
page 1 has a form, which will submit to eg. product.php?action=add. In product.php you can route the 'add' action to the function add_product() (or whatever). Then when the product is added, just header the user back to the main page (or whatever page you'd like). This immediately tackles the problem with refresh-posts (user refreshing the page which will send the same data again).
following mvc imagine you have a controller Product which handles all the product actions. The skeleton could look like this (assuming function action_x will be executed when yoursite.com/product/x is requested):
class Product_Controller {
function action_show() {
}
function action_update() {
}
function action_delete() {
}
}
if your framework supports a default action of some sort you could route your actions:
function action_default() {
if(method_exists(array($this, 'action_'. $_POST['action']))) {
return call_user_method('action_'. $_POST['action'], $this);
}
}
ofcourse the same can be achieved without controller classes;
if(function_exists('action_'. $_POST['action'])) {
call_user_func('action_'. $_POST['action']);
}
function action_show() { }
...
and to illustrate the discussion in the comments;
function action_update() {
// do some update logic, query an UPDATE to mysql etc.
if($result) {
// optionally save a success message
Message::add('Your record has been updated');
header('Location: main_page.php'); // or another intelligent redirect function
} else {
Message::add('Sorry, something went wrong');
header('Location: error_page.php'); // or also main_page
}
}
This will also keep your code cleaner, as updating/adding/deleting stuff is radically different from showing stuff, this will prevent you from mixing up stuff. You could even call the show function from within the update function if you want to skip the redirect.
But in the end it's a matter of choice, led by pragmatism or your framework ;)
I hope this'll explain everything a bit, don't hesitate to ask for clarification
if you want to separate the logic from the interface then you can simple create new file and put the all logical and database related code in that file and include OR require that file in the view file
like
view.php interface file and
logic.php is your logic file then
first line in view.php is
require_once(logic.php');
and all the logic is in this files
simple MVC
Well, it seems I have to explain.
It absolutely does not matter how much IF statements you have in the POST handler. Your current design is okay, and there is no reason to ask nor change it.
The only thing that you may wish to add to your design is a front controller, which will take both entity (cart) and action("add") and call add() method of $cart class. these methods you may store one under another in the class source.
Though it is quite huge improvement, requiring great rethinking of the whole site architecture. So, you may stick with your current one.
As for your other question, how to display errors, here is an answer: php redirection not working

When form validation fails, how to pass error information for new try?

I'm developing a form validation class in PHP. When form validation fails, I can easily redirect again to the form's html page but without error information. I would like to redirect to the form's page with the specific errors about which fields failed and why.
How should I do this? Should I send information back via GET or POST? and in which format? Would really to see some code to see how people tackled this problem.
Thanks!
You could use the header() function. So just check the fields that are posted:
if(!$form->valid()){
$msg = "Form is not valid";
} else {
//Don't know if you want this
$msg = "Form is valid";
}
header("Location: [page where you came from]?msg=" . urlencode($msg));
Then in the page where you're redirecting to use
if(isset($_GET['msg]))
echo urldecode($_GET['msg']);
to echo the message. If you are using other get variables in the location of the header function, of course, use &msg=" . urlencode($msg). (You may also want to return the values that the user submitted, so the user doesn't have to fill out the entire form again if he makes 1 mistake.
I agree with user187291's suggestion of using $_SESSION because:
It doesn't hijack the URI like using $_GET (you would never want a static link to a status message). Users could press "back" to the page with your form and still see a status message because the URI says so.
Print and unset it in the same run, you won't be able to use it more than once (which is what you want?!)
If you're going with AJAX, $_GET is more widely used for retreiving values, which you are doing from the validation controller.
there are number of approaches
pass errors in GET when redirecting back like you said
use sessions to store error info, on the form page check Session for errors
do not redirect after failure, just output form again along with error messages
ajax submits
which one to use depends on the application. For most apps sessions method is most appropriate.
Something like this:
// Pseudo Code
function isValid($parm) {
$return = false;
if(preg_match(/^[a-zA-Z]+$/, $parm) {
$return = true;
}
return $return;
}
$firstname = $_GET["fname"];
$lastname = $_GET["lname"];
$validFirstName = isValid($firstname);
$validLastName = isValid($lastname);
if($validFirstName == true && $validLastName == true) {
echo "It's all good";
// Do what you need to like, Submit
} else {
echo "Please retry";
// Display error message
}
I use a class to interface with $_POST, similar to the following:
// create the object
$post = new PostData();
// register your requirements... write whatever methods you need
// for each call,read $_POST, check criteria, and mark the field
// as good or bad...
$post->required ('LastName');
$post->required ('FirstName');
$post->numeric ('Age');
$post->optional ('MiddleInitial');
$post->regExp ('/\d{3}/','AreaCode');
$post->email ('Email');
// check the status
if (!$post->isValid ())
{
$_SESSION['FailedPostData'] = $post;
header ('Location: page.php');
}
// normal form processing
Then, on page.php, you can see if FailedPostData is in the session, read it to find the info entered last time, as well as which fields that failed. I use a template engine with macros that let me easily re-populate the form inputs and mark the failures. Otherwise you might end up with lots of code for a simple form...
You'll also need a mechanism to be sure that stale FailedPostData doesn't hang around in the session and confuse things.
I am doing it this way. Beginner in php so not sure if this is the best way to do:
HTML Form Page:
<form id="abc" method="post" action="validate.php">
PHP Page
..validation conditions..call a function if things do not match
function display_error($error) {
echo "<html><body><link href='style.css' rel='stylesheet' type='text/css'><br><center><h2>";
echo "$error";
echo "</h2></center><br><br>";
echo "<center><input type='button' value='Go Back' onClick='history.go(-1)' style='width:100px; height:28px; font-size:16px'></center>";
echo "</body></html>";
}
Clicking on the back button takes you back to the html page with the data intact.

Categories