I am working on 'Forgot Password' functionality using YII framework. The flow is as such -->
At the Login Page , a Link 'Forgot Password' is provided. On clicking it, a new view is rendered where the user needs to put his EMail Address . A mail is delivered to the Mail ID and a link is provided in that mail on clicking of which the User will be taken to 'RESET Password' PAge where he can SET a new password.
I am working with Sessions for fulfilling this scenario.The issue is that Session is being overwritten and only the latest entered EMAIL Address(User) can RESET the password (when tried by entering Multiple EMAIL ID's one after other).
1)Firstly I have started the session after the 'Submit Button' is clicked.A random string is kept in the session and send to the EMAIL . When User Clicks on the reset link , the RESET page is opened and if the string matches with the Session String then the Password can be reset .
All these works fine if worked with only one EMAil . if i enter two Email ID's .. I get the mail on Both with reset link generated ,,,, but when I click on the reset link of first Mail ID ,,, i get Error messsage where as when i click the reset link received in second MAil Address ,, then it works .
public function actionForgotPassword()
{
$model = new ForgotPasswordForm;
$userModel = new UserDetails;
if(isset($_POST['ForgotPasswordForm']))
{
$model->attributes = $_POST['ForgotPasswordForm'];
// validate user input and redirect to the previous page if valid
if($model->validate())
{
$getMail = $_POST['ForgotPasswordForm']['email'];
$user = UserDetails::model()->findByAttributes(array(
'email' => $getMail
));
if($user)
{
session_start();
$sessionString = $model-> genRandomSaltString();
Yii::app()->session['identityString'] = $sessionString;
///Below is the MAIL function
}
}}}
The Code on RESET PAge is
public function actionNewPassword()
{
session_start();
$model = new ChangePasswordForm;
$userModel = new UserDetails;
$email = Yii::app()->request->getParam('tag');
$getSessionKey = Yii::app()->request->getParam('key');
//print_r($_SESSION);die;
$catchSessionValue = Yii::app()->session['identityString'];
if(!empty($_SESSION) && !empty($catchSessionValue))
{
if($catchSessionValue == $getSessionKey && $email !== null)
{
$user_arr = UserDetails::model()->findByAttributes(array('email' => $email));
$user_name = $user_arr['username'];
$user_id = $user_arr['id'];
Yii::app()->user->setFlash('info', "Enter your New Password here.");
if(isset($_POST['ChangePasswordForm']))
{
$this->render('changepassword',array('change_pw_form'=>$model,'user'=>$user_arr));
}
else{
$this->render('changepassword',array('change_pw_form'=>$model,'user'=>$user_arr));
}
}
else
{
Yii::app()->user->setFlash('error', "Something went Wrong. Try Again!");
$this->render('changepassword');
//$this->redirect(Yii::app()->createUrl('site/login'));
}
}
else
{
$user_arr = UserDetails::model()->findByAttributes(array('email' => $email));
Yii::app()->user->setFlash('error', "Sorry ! The link has been expired. Please try again.");
$this->render('changepassword',array('change_pw_form'=>$model,'user'=>$user_arr));
// $this->redirect(Yii::app()->createUrl('site/login'));
}
}
You're overriding the value over and over again and hence only the last email's 'identityString' is being stored.
Why?
For the same 'browser session' (meaning you didn't close the browser or open the page in a different browser), a session remains the same. (Unless explicitly destroyed in your php code)
And as long as the session remains the same, you are effectively overriding the 'identityString' session value each time. Meaning, the random string generated while sending the first mail is overridden by the random string generated while sending the second mail. That is why you are not getting the error in the second one.
Sessions are not useful in this case, because the values you are storing are not accessible once the user closes his browser or uses a different browser or a device to click on the link in the mail.
You would store such information in a database, or a cache. If you don't want to use a db, file caches are available in Yii. Use Yii::app()->cache->set($id, $value); Where $id could be a unique string generated from the user's email address and $value is the $sessionString
Example:
$id = 'identityString.'.md5($getEmail);
// 'identityString.9e107d9d372bb6826bd81d3542a419d6'
Yii::app()->cache->set($id, $sessionString);
And you will retrieve this again:
$id = 'identityString.'.md5($email);
$catchSessionValue = Yii::app()->cache->get($id);
And here's a simple explanation of how sessions work:
Whenever a session is initialized on your server, the browser stores a session cookie with a unique value. This cookie is passed around with every request to your server from then. The unique value is used to identify the session, and the server retrieves all the variables initialised for that session.
The browser loses the session cookie when it is closed and hence access to that session is lost.
Also, a fellow stackoverflow user wrote this, go through it:
http://machinesaredigging.com/2013/10/29/how-does-a-web-session-work/
Related
I would like to create a wordpress user with contributor privelages, remotely. However, I would like to also create their wordpress account using an email that I manipulate by using their id (from login on my site) and #example.com. So it would essentially be: id##example.com. I am very new to programming. I have looked and looked and just continue to scratch my head. What would be best practice for doing this? Any examples, resources, explanations would be appreciated!
I was thinking of creating a link in their account page that when the logged in user clicks it it will redirect them to a page that will create their user account within wordpress framework. They would have to be logged into my site to access.
I am not sure how to do the email portion of your question. Although, I would like to know how to meld the two together. However, if you are needing unique emails for wordpress you can by-pass this required section (required if using wp dashboard to create user). I found this recently.
You could simply:
$user_name = //however you get your unique identifier this will be their screen name
$user_id = username_exists( $user_name );
if ( !$user_id and email_exists($user_email) == false ) {
$user_id = wp_create_user( $user_name, $user_email );
wp_update_user(array(
'ID' => $user_id,
'role' => 'contributor'
));
}
If your users actually do have an email account on your server and you want them to receive emails from wordpress.. this will not fix your situation.
there are many ways to do this. the cleanest would probably at the moment be to use the Wordpress API together with JWT authentication.
Here is an easier solution. On the Remote Wordpress Installation you stick something like this into your functions.php
function remote_create_user() {
$token = (isset($_GET['token'])) ? sanitize_text_field($_GET['token']) : '';
$action = (isset($_GET['action'])) ? sanitize_text_field($_GET['action']) : '';
//this is not particularly secure, but let's assume your wordpress page has https which should encrypt the url...
//im just setting some random string to compare to
if ($token != '712031ff105541219fcc741d99a9addd' || $action != 'createuser') {
return;
}
$username = sanitize_text_field($_GET['username']);
$email = sanitize_text_field($_GET['email']);
//making sure the user doesn already exist
$user_id = username_exists($username);
if (!$user_id and email_exists($email) == false) {
$random_password = wp_generate_password($length = 12, $include_standard_special_chars = false);
//creating the user
$user_id = wp_create_user($username, $random_password, $email);
if ($user_id) {
//here you could send the user a welcome mail. if you want, include the password in the mail or just make him press the "forgot password" button
//wp_mail($to, $subject, $message);
echo "User created";
}
} else {
echo "User already exists.";
}
}
add_action('init', 'remote_create_user');
On the system you want to send the command from, you can then do something like this (on the serverside, you can't to this from the browser, because the "authentication" token will be visible in the javascript...
$createuser = file_get_contents('https://yourdomain.com/?token=712031ff105541219fcc741d99a9addd&action=createuser&username=test3&email=test3#test.com');
//depending on the result in $createuser, give an error message or redirect him to your wordpress login page or something
i hope this gives you some ideas.
Edit: Aboves init function is missing a wp_die() at the end. we dont want the whole page rendered here. also, this is just a quick & dirty solution.
Look into Wordpress Rest API or also custom endpoints.
I would like to implement multiple user login show like gmail login. See below image:
Current I'm using COOKIE to get the USERID. But it only give me the last USERID. not all.
Here is PHP to set COOKIE:
setcookie("cookielogin[userLoginRemembered]", $dataLoginQuery['USERID'] , $time + (60*60*24*7));
What I want is, to show all user ever logged in and display it using COOKIE.
Is it possible?
Because you only store last logged user id into cookie, and it overrides old value
Cookie only stores raw text, so if you want to store a list (array), you have to serialize it (by your own way or using serialize() function). This
sample code below uses PHP's serialize():
$lastLoggedUserId = '123';
if (!isset($_COOKIE['cookie_key_for_logged_users'])) {
$cookieLoggedUserIds = [$lastLoggedUserId];
} else {
// unserialize
$cookieLoggedUserIds = (array) unserialize($_COOKIE['cookie_key_for_logged_users']);
$cookieLoggedUserIds[] = $lastLoggedUserId;
}
// just to make sure no duplicated user id to be stored
$cookieLoggedUserIds = array_unique($cookieLoggedUserIds);
setcookie('cookie_key_for_logged_users', serialize($cookieLoggedUserIds));
print_r(unserialize($_COOKIE['cookie_key_for_logged_users']));
I've not tested this code, but it's easy to test and tweak.
You need to append the information in the cookie.
There is no append for cookies so what we need to do is read it's current value, add current string and write a new cookie.
$currentvalue = $_COOKIE["cookielogin[userLoginRemembered]"];
If(strpos($currentvalue, $dataLoginQuery['USERID']) !== false){
Echo "username exist in cookie already";
}else{
setcookie("cookielogin[userLoginRemembered]", $currentvalue .",". $dataLoginQuery['USERID'] , $time + (60*60*24*7));
//Here I set the value of cookie as current value and dataloginquery.
}
Output:
Var_dump(explode(",", $_COOKIE["cookielogin[userLoginRemembered]"]));
// Dumps the array of usernames that is comma separated.
I have two MySQL tables. The first one is for the user's credentials i.e. username, password, business_id (system generated). The second one has the user's profile for multiple entities e.g. business name, location, profile_id and business id (system genrated - the same number for the business_id).
The user can edit the details of their business details i.e. their details in the second table. The business id would be say 'abcdef' and profile id would be say 1234567, if they have a second business profile it would be say 1235879.
In order to edit each profile I would have to have the following URL
Edit Business Profile
For the second one it would be
Edit Business Profile
In turn when the a href is clicked the url in the browser would be edit_profile.php?id=1234567 and for the second one would be edit_profile.php?id=1235879
Would it be possible that instead of having edit_profile.php?id=1234567 and edit_profile.php?id=1235879 in the URL I would have edit_profile.php?id=1234567 and for the second one would be edit_profile.php
I don't want the User to see the id i.e. have only edit_profile.php
Ideally, I would like to use a PHP solution, please.
Yes, it is possible, but not exactly what are you trying to do
Solution #1
Intoduction
First of all, it should work only on users who are currently logged in and are trying to see their profile. The final results to reach is to not display ID in URL if ID is equal to current logged user's ID. It is more common than Solution #2 but if you want to hide all IDs, skip this solution.
Pluses:
There is not too much to change, just add a few more lines for checking current user ID
You can still use <a></a> tags for Edit Business Profile links.
Minuses:
Only current logged user's ID will be hidden in the URL
So what to do...
You probably use sessions to let users remain logged in even if they refreshed the page. You are on the right path, but you should add at least one more element to $_SESSION (Profile identification, so we can call it as profile_id for example).
Assume you are using this login formula:
function check_login($username, $password)
{
// query to find user with these inputs (encrypted password, prepared statements, etc)
if($query->num_rows > 0) // user exists
{
// fetch your query
// ...
session_start();
// set the session probably user is logged
// some return on success (probably redirect)
}
else
{
// some return on false
}
}
Now you should add one more $_SESSION element to save your current profile_id value:
session_start();
// ...
$_SESSION['profile_id'] = $result->profile_id; // <--- THIS IMPLEMENT
// some return on success (probably redirect)
1/2 is done!
Half of the problem is already finished, now all you need to do is compare $_GET input with $_SESSION.
Again, assuming your edit_profile.php file looks like this:
if(isset($_GET['id']) && !empty(trim($_GET['id'])))
{
$profile_id = intval($_GET['id']);
// ...
}
else
{
// probably an error profile id is not defined
}
// rest of the code ...
So now instead of error profile id is not defined we can assign to $profile_id variable index profile_id of superglobal $_SESSION:
else
{
$profile_id = intval($_SESSION['profile_id']);
}
Notice that I am assuming you have condition to reject access to this script, if user is not logged (some condition at the start).
Now your code should work but maybe you are asking the question what if user knows his ID and types it into URL?
So you have two choices:
Let it be as it is
Add condition to check if $_GET['id'] equals to $_SESSION['profile_id'] then redirect to edit_profile.php
Final thoughts...
Maybe if you are generating the list of the users, where the user can edit the others' users profiles including himself's, you want to remove id parameter of the edit_profile.php URL if the user's ID is equal to current ID in fetch loop. You can inspire by this simple function:
function generate_profile_edit_url($id)
{
session_start(); // for the case, you don't have started session yet
return 'Edit Business Profile';
}
Just in every fetch iteration you will use this function, like in the example below:
// ...
echo generate_profile_edit_url($result->profile_id);
// ...
Solution #2
Introduction
This solution will reach to the editing user's profile without any ID parameter in URL. It is designed for situation where user has rights to edit someone else's profile (for example, a moderator or an admin) and you still don't want to have the users' ID in the URL.
Pluses:
No ID parameter in URL needed for all users
Minuses:
you have to change every profile link to little form using POST action without JavaScript knowledge
no more <a></a> links for profile edit, again without JavaScript knowledge
users are still able to get their id if they want to
So what to do...
Firstly, we need to change edit_profile.php file. We have to recieve $_POST data containing target's profile_id.
Like in Solution #1, assume your edit_profile.php looks like:
if(isSet($_GET['id']) && !empty(trim($_GET['id'])))
{
$profile_id = intval($_GET['id']);
// ...
}
else
{
// probably an error profile id is not defined
}
// rest of the code ...
Most of the changes will be just replacing $_GET with $_POST:
if(isSet($_POST['profile_id']) && !empty(trim($_POST['profile_id'])))
{
$profile_id = intval($_POST['profile_id']);
// ...
}
else
{
// probably an error profile id is not defined
}
// rest of the code ...
For this file, it is enough.
Now there is some more work to do if you have a placed profile links in different files. But we can make it easier using one simple function like this:
function get_profile_edit_button($profile_id)
{
$html = '<form action="edit_profile" method="POST">';
$html .= '<input type="hidden" name="profile_id" value="' . intval($profile_id) . '">';
$html .= '<input type="submit" value="Edit Business profile">';
$html .= '</form>';
return $html;
}
The last thing is replace current edit profile links with this function. For example you have fetch loop of users:
// ...
echo 'Edit Business Profile';
// ...
So you will replace this string with your function get_profile_edit_button():
// ...
echo get_profile_edit_button($result->profile_id);
// ...
Final thoughts...
As I mentioned in minuses, profiles' ids cannot be totally hidden. If someone opened Source code of your page, he can see profile_id in hidden form type:
<input type="hidden" name="profile_id" value="1234567">
It is only on you what solution you prefer, but I can recommend you Solution #1. There is nothing bad about having IDs in URL. Stack Overflow has it too as you can see it on questions, answers, comments and users.
Useful resources:
PHP Session Security
PHP form token usage and handling
When logging in, try saving the user ID and business ID inside session.
As for example..
$logged_in = some_logic_stuffs();
if($logged_in){
session_start();
$_SESSION['user_id'] = SOME_ID_FETCHED_FROM_LOGIN_LOGIC;
$_SESSION['business_id'] = SOME_ID_FETCHED_FROM_LOGIN_LOGIC;
}
Now, when user goes to edit_profile.php, do
session_start();
$business_id = $_SESSION['business_id'];
$user_id = $_SESSION['business_id'];
For the login logic, try reading this tutorial:
http://www.formget.com/login-form-in-php/
If the user can edit multiple business profiles, the $_SESSION solutions would not work. You would need to disguise what gets sent to the address bar:
You would need to change your code to POST the data rather than sending it as a GET request.
To do this you could either use JavaScript to fake a form post on the link click, or wrap your link in a form tag and set method="POST".
POST sends the data "behind the scenes" rather than exposing it in the browser. I should add that this would still be visible to anyone wanting to discover your IDs, but it would hide it from the casual user at least.
If you really wanted security, #BobBrown's suggestion to tokenise would be a great way forward. You may find, however, that just hiding the ID from display on-screen is enough. Just make sure your user management system will restrict who can edit a particular business.
Try this
<?php
session_start();
include('dbconnect.php');
if(isset($_SESSION['username']))
{
$username = $_SESSION['username'];
$userid = $_SESSION['id'];
}
else
{
$_SESSION['id'] = "";
$_SESSION['username'] = "";
}
if($username <> "")
{
$username = 'username';
$userid = 'id';
}
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 900))
{
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
?>
then
<?php
#if the form is set (meaning that the information was submitted then define what the parameters are for each
if(isset($_REQUEST['username']) == TRUE)
{
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
#make sure there are no blank fields
if($username == "" OR $password == "")
{
echo '<p class="text-danger">Please enter a Username and Password</p>';
}
else
{
$userid = finduser($username, $password);
if($userid > 0)
{
loginuser($userid);
}
else
{
echo '<p class="lead text-danger">The Username and/or Password enter is incorrect</p><br />';
}
}
}
?>
after that then this
<?php
if(isset($_SESSION['username']))
{
if($_SESSION['username'] <> "")
{
//do something
}
else{
//form or something else
?>
<form>form goes here</form>
<p> or something else you want</p>
<?php
}
}
?>
Start your PHP with session_start(); then when the user logs in make a session value for the ID:
$_SESSION['profile-id'] = 1235879; //Select it from database
after in your edit_profile.php do that:
if (!isset($id)) {
$id = $_SESSION['profile-id'];
}
And then edit the $id.
Store the id in session on the first page:
$_SESSION['id'] = 12345;
And on edit_profile.php you can get the value by:
$id = $_SESSION['id'];
And start the session on every page by session_start();
Easiest and simplest way to handle your situation if you want to use Id or any information in URL and pass it through URL
then you can have a scret combination with your values like below
Firt you have to encode the value with your secret stuff for example
$sshhh="ITSMY_SECRET_VALUECODE";
$encrypted_id = base64_encode($your_value . $sshhh);
Then pass it (encrpyted_id) in URL
for example href="all-jvouchers.php?id=<?= $encrypted_id; ?>
and while getting value use below code to get back your value
$sshhh="ITSMY_SECRET_VALUECODE";
$decrypted_id_raw = base64_decode($_GET['id']);
$decrypted_id = preg_replace(sprintf('/%s/', $sshhh), '', $decrypted_id_raw);
Use $decrypted_id wherever and however you want to securely
I have a web server with Magento 1.4.0.1 installed. I have another web site that shares credential with it. I've managed to check if the customer is logged in or not (after having changed the cookies location in Magento), but things got complicated when I also tried to figure out if an admin was logged in. I can only get the proper answer for the first session I asked for (either the customer OR the admin, the second one is NEVER logged in).
How can I have both answers?
Here is the code I'm using to test that out:
require_once '../app/Mage.php';
umask(0) ;
Mage::app();
// Checking for customer session
Mage::getSingleton('core/session', array('name'=>'frontend') );
$session=Mage::getSingleton('customer/session', array('name'=>'frontend') );
if ($session->isLoggedIn()) {
echo "Customer is logged in";
} else {
echo "Customer is not logged in";
}
// Checking for admin session
Mage::getSingleton('core/session', array('name'=>'adminhtml') );
$adminsession = Mage::getSingleton('admin/session', array('name'=>'adminhtml'));
if($adminsession->isLoggedIn()) {
echo "Admin Logged in";
} else {
echo "Admin NOT logged in";
}
So with the code like this, the admin is never logged in. If you put the part about the admin first, then the customer is never logged in. It seems like I'm missing a line between the two requests.
This may be the same problem than this unanswered question: Magento how to check if admin is logged in within a module controller
This seems like a popular problem, but I could not find the proper solution...
Thanks for your help!
I've found that "bug-feature" from another angle of view (trying to login customer from adminside), but still found the cause.
The problem is with session_name() function. If you go to Mage_Core_Model_Session_Abstract_Varien you'll see there that the session object is using standart PHP session functions and PHP can't handle two sessions at the same time.
You session id for adminside is stored in cookie adminhtml, while for clientside your session id is in frontend cookie. Then in adminside you have session ID initialized by adminhtml cookie. When in adminside, your customer/session object is stored inside something like $_SESSION['customer'] (haven't checked exact key) inside PHP session for ID stored in adminhtml cookie. This means that customer/session object is refering to different sessions when inside admin and client parts of magento.
What you need to do is switch the session data. You can do this with the following code:
$switchSessionName = 'adminhtml';
$currentSessionId = Mage::getSingleton('core/session')->getSessionId();
$currentSessionName = Mage::getSingleton('core/session')->getSessionName();
if ($currentSessionId && $currentSessionName && isset($_COOKIE[$currentSessionName])) {
$switchSessionId = $_COOKIE[$switchSessionName];
$this->_switchSession($switchSessionName, $switchSessionId);
$whateverData = Mage::getModel('mymodule/session')->getWhateverData();
$this->_switchSession($currentSessionName, $currentSessionId);
}
protected function _switchSession($namespace, $id = null) {
session_write_close();
$GLOBALS['_SESSION'] = null;
$session = Mage::getSingleton('core/session');
if ($id) {
$session->setSessionId($id);
}
$session->start($namespace);
}
Here is what I use..
Mage::getSingleton('core/session', array('name'=>'adminhtml'));
$session = Mage::getSingleton('admin/session');;
if (!$session->getUser())
{
die("You aren't an admin!");
}
It is quite simple but not a recommended solution. I myself spend number of hours to do this.
For, windows based server try below solution:
$sessionFilePath = Mage::getBaseDir('session').DS.'sess_'.$_COOKIE['adminhtml'];
$sessionFile = file_get_contents($sessionFilePath);
$exp_cookie = explode(';',$sessionFile);
if(count($exp_cookie) > 100)
{
return "login";
}
return "expire";
For, Linux based server try below solution:
$sessionFilePath = Mage::getBaseDir('session').DS.'sess_'.$_COOKIE['adminhtml'];
$sessionFile = file_get_contents($sessionFilePath);
$exp_cookie = explode('--',$sessionFile)
if(count($exp_cookie) > 10)
{
return "login";
}
return "expire";
Thanks,
Kashif
Here is a simple script to check admin is logged or not and if logged get admin details of Magento.You can call to the session and the call to user function to get all details.
$userDetails = Mage::getSingleton('admin/session'); // Get data from the session
$userID = $userDetails->getUser()->getUserId(); // Get user ID
$userID = $userDetails->getUser()->getEmail(); // Get user Email
Please refer to http://webexplorar.com/magento-admin-details/ for more details.
I have a problem which has only just surfaced itself.
I'm working in a MVC environment. The method names in my interface class match those of the request module and action i.e. ?module=test&action=action would result in a method called public function test_action() { }
In this particular problem, I have a form which submits to itself. If validation passes, a record is created and I then show the template of another module. This module expects a series of post variables as it is used in two modules.
The problem I'm having is that, if the user successfully passes the validation and attempts to F5 the page, another new record is created etc.
How can I prevent this from happening?
Normally I would header redirect after a successful insert but in this instance I can't.
I would take it a complete other way. I even find redirection an incorrect way of handling this, since changing locations is not meant to overcome logic/form troubles.
The correct solution is:
Add a unique hash to your form in a hidden input
Store the hash in a server-side session
When the form is send, validate the hidden input hash with the hash on your server
Only execute row insertion when the form validates correctly.
If you are working with Zend Framework, there is a Zend_Form_Element_Hash class for you.
Developer error:
You need to create a handler page which:
validating sent data
insert row
redirect user
You can / should re-direct to a new page after successful insertion.
As you are working in MVC, you can add a new controller that just calls the view you want to show.
Here is what I do it. This is working for me. Hope it can help anyone else.
//+++ start token +++
//This is to prevent duplicate entry on page reload (F5). 19. If I enter all values, press Record in journal and then press F5, the same values are recorded one more time. Need to prevent
// 3rd. $token_hash_from_input get value of input field name name="' .$_SESSION['token_hash'] .'"
$token_hash_from_input = $_SESSION['token_hash'];
//echo $token_hash_from_input .' token_hash_from_input<br>';
//echo $_POST[$token_hash_from_input] .' $_POST[$token_hash_from_input]<br>';
//var_dump($token_hash, $_POST);
// 4th. $_SESSION['token'] created/set in 1st. Then it as if goes around (at first to input field then after page reload returns here). However $_POST[$token_hash_from_input] is value received directly from input field. User click post and input field value is passed to $_POST[$token_hash_from_input]. Here I compare both.
if ( $_SESSION['token'] != htmlspecialchars($_POST[$token_hash_from_input]) ) {
$token_error .= 'yes';
//echo 'session token and token from input field are not the same <br> ';
}
else {
//echo 'session token is equal to post$token_hash)<br>';
}
// 1st. Create token and pass it to session
$token = sha1(uniqid(mt_rand(), true));
$_SESSION['token'] = $token;
//echo $_SESSION['token'] .' new $_SESSION[token]<br>';//after each page reload new token created. Then this token passed to input form (hidden field). value="' .$_SESSION['token'] .'"
// 2nd. Create token_hash and pass it to session. Token hash is to name input fields name and id. I may not use $token_hash and $_SESSION['token_hash']. Instead of this I can use name="token" and id="token".
$token_hash = sha1(uniqid($time_when_form_submitted .'token' .$_SERVER["REMOTE_ADDR"]));
//echo $token_hash .' $token_hash<br>';
$_SESSION['token_hash'] = $token_hash;
//echo $_SESSION['token_hash'] .' new SESSION$token_hash<br>';
// +++ end token +++
Input field like this
<input type="hidden" name="' .$_SESSION['token_hash'] .'" id="' .$_SESSION['token_hash'] .'" value="' .$_SESSION['token'] .'">
or
<input type="hidden" name="<?php echo $_SESSION['token_hash'] ?>" id="<?php echo $_SESSION['token_hash'] ?>" value="<?php echo $_SESSION['token'] ?>">
I suppose code can be improved (I have no good knowledge php etc)
"Normally I would header redirect after a successful insert but in this instance I can't."
are you facing some error in doing that?
If for whatever reason you can't redirect (Which sounds peculiar) you can use the 'same'
mechanism used for data validation to flush the forms after a successful insert.
But that's a really ugly way to go.
One of most common issue which many of the web developers face in their web applications, is that the duplicate records are inserted to the Database on page refresh. If the web page contains some text box and a button to submit the textbox data to the database. In that case when the user insert some data to the textbox and click on the submit button, it will save the record to the Database and then if the user refresh the web page immediately then the same record is again saved to the database as there is no unique keys that can be used to verify the existence of the data, so as to prevent the multiple insertion.
From this behavior we can definitely know that, on the page fresh the button click event is fired.
To avoid this problem we can try this method as discuss below.
On page load event save the date/time stamp in a session variable, when the page is first loaded, a Session variable is populated with the current date/time as follows:
*void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
Session["update"] = Server.UrlEncode(System.DateTime.Now.ToString());
}
}*
On the page's PreRender event, a ViewState variable is set to the value of the Session variable as follows:
void Page_PreRender(object obj,EventArgs e)
{
ViewState["update"] = Session["update"];
}
Then these two values are compared to each other immediately before the database INSERT command is run.
If they are equal, then the command is permitted to execute and the Session variable is updated with the current date/time, otherwise the command is bypassed as given below:
void btnSubmit_Click(object obj, EventArgs e)
{
string name = "";
string qualification = "";
if (Session["update"].ToString() == ViewState["update"].ToString())
{
if (txtName.Text != "" || txtName.Text != null)
{
name = txtName.Text.ToString();
}
if (txtQualification.Text != "" || txtQualification.Text != null)
{
qualification = txtQualification.Text.ToString();
}
//--- Insert data function should be execute here
string strSql = "INSERT INTO Testdata (Name,Qualification) VALUES ('" + name + "','" + qualification + "')";
SqlConnection ANConnection = new SqlConnection(ConnectionString);
ANConnection.Open();
SqlCommand ANCommand = new SqlCommand(strSql, ANConnection);
ANCommand.ExecuteNonQuery();
ANConnection.Close();
ANConnection.Dispose();
//--End of save data
lblMessage.Text = "Inserted Record Sucessfully
Session["update"] = Server.UrlEncode(System.DateTime.Now.ToString());
}
else
{
lblMessage.Text = "Failure – Due to Page Refresh";
txtName.Text = "";
txtQualification.Text = "";
}
}