Real solution for form repeat submit problem PHP code

Source: Internet
Author: User
Tags character set current time extend hash html tags md5 php code valid

Pre-used JS form to prevent duplicate submission method

The code is as follows Copy Code

<script type= "Text/javascript" >
var checksubmitflg = false;
function Checksubmit () {
if (!CHECKSUBMITFLG) {

First time Submission
CHECKSUBMITFLG = true;
return true;
} else {

Repeat Submission
Alert ("Submit again!");
return false;
}
}
</script>

The following three methods are called separately

<form onsubmit= "return Checksubmit ();" >

<input type= "Submit" onclick= "return Checksubmit ();"/>

<input type= "button" onclick= "document.forms[0].action= './test ';d ocument.forms[0].submit (); return CheckSubmit ( ); "/>

so if I make a form directly, and then submit it to/test, the above agent is a device, then how do we solve this problem

If you already know how to solve this article may not be suitable for your taste, Paperen here also intends to start from the basis of discussion, so I hope that one step to see the solution you may not be appropriate, so please note. so~ start.

Paperen Think you must know what the form is, the form element is the form, the General page needs to enter the place must use the form element, also very common, the general code is as follows:

  code is as follows copy code

     <form
    
    method= "POST"
    <p>
    <label for= "Test" > casually enter something www.111cn.net</label>
    <input type= "text" name= "data" id= "test"/>
    </p>
    <p>
    <input type= "Submit" value= "submitted" name= "Submission"/>
    </p>
& nbsp;   </ul>
    </form>

The focus is actually form and input elements, p element is only Paperen privately added, to follow the instructions without any impact, in fact, is very simple, the so-called input is entered, you can fully interpret the input elements as a user input, Only some of the attributes (type) cannot be input (this is the submit), and the form element you can completely interpret as a bag that takes all the user input data to the server after it is loaded into it, but the method attribute is notable for the form element. In general there are get and post two methods, do not think too complex (because the depth does not need to understand, for the subsequent content is not too much relationship, if interested may wish to use the browser's debugging tools to view the request header information and send information, such as Firebug), show that is, The value of all input elements will appear in the Address bar when you submit the form using get, and post will not, such as the browser address bar when you submit this form using get

The code is as follows Copy Code

Http://localhost/mytest/token/form.php?data=test&submit=%E6%8F%90%E4%BA%A4

Post is not visible in the address bar, you can use Fiebug to see the following information

It is easy to assume that get is an explicit transfer of data, while post is an implicit transfer of data, but there is a big difference is that the post supports more and larger data transfer.

Next, when the form code is written, let's write the server script (PHP here). Very simple ~

  code is as follows copy code
<?php
    if (isset ($_post[' submit ')) {
   /form Submit processing
    $data = isset ($_post[' data '])? Htmlspecialchars ($_post[' data '):
    
    ';
   // Insert or UPDATE database
    $sql = INSERT INTO Test (' string ') VALUES (' $data ');
   / /do query
    echo $sql;
   }
   

Because this is the post transfer data, so using PHP's $_post global variable to get the form submission of data, all the use of the POST method of the form data submitted to the server will be saved in this $_post global variable, may wish to try Print_r ($_post) You will understand this variable.

First check whether there is a submit in the $_post array, if the existence of the proof is the form submitted, as if there is a asp.net called IsPostBack, but this is not so rigorous, but it does not matter after the problem will be solved.

Then you receive the input box data, which is $_post[' data ', and don't forget to use Htmlspecialchars to do HTML filtering on this, because it prevents you from entering HTML tags or JavaScript as a problem (seemingly an XSS vulnerability). Finally, the stitching into the SQL statement into the database ran (just here Paperen did not use a lot of detail to manipulate the database functions such as mysql_query, interested in the completion of its own). Congratulations, here you have successfully completed a data entry function, but there is a place you have to improve it, insert the data must give the operator a hint of it ~ ~ at least prompted me to fail or successful operation. So the entire code paperen written like this.

The code is as follows Copy Code

&lt;?php


if (Isset ($_post[' submit ')) {


Form submission Processing


$data = Isset (





$_post[' data '])? Htmlspecialchars ($_post[' data '): ';


Connect


mysql_connect (' localhost ', ' root ', ' root ');





Select DB


mysql_select_db (' Test ');


Set character set to prevent garbled


mysql_query (' Set names "UTF8");


Sql


$sql = "Insert





Into ' token ' (string) VALUES (' $data ');


Query


mysql_query ($sql);


$insert _id = mysql_insert_id ();


if (





$insert _id) {


$state = 1;


} else {


$state = 0;


}


}


?&gt;

<?php if (isset ($state)

&& $state) {//Data insertion Success?>

<p> Insert Success <a href= "form.php" > Return </a></p>

<?php} else {//failed or no insert move

As?>

<form method= "POST" >

<p>

<label for= "Test" > Random input points </label>

<input type= "Text"

Name= "Data" id= "test"/>

</p>

<p>

<input type= "Submit" value= "submitted" name= "Submission"/>

</p>

</ul>

</form>

<?php}?>

HTML declaration and head and body are omitted, compared to the beginning of the code is actually the main implementation of the actual insert database action and given the operation feedback (through the $state variable), may wish to copy the code and then try (of course, according to their actual situation to modify the database operation part of the code). Code normal, logical no problem, but there is a problem, that is, after the success of the display insert and then refresh the page will perform the form processing action, and inserted again data! This is called a repeat insertion problem. You can think about how to solve the problem before releasing the solution.

Do you think that receiving data and display processing results are the same page so that this problem can be caused? Yes, you can also think that, with some debugging tools you'll find that the browser also retains the Post's data, so the post data is resubmitted once the form has been submitted and then refreshed.

If there is a way to empty the browser this temporary saved post data will not solve the problem, but the server is not able to do this, because this is the browser itself, or we are redirected or otherwise refresh or will repeat the submission of data.

So far you may have learned the meaning and the problem of repeated submissions, if you do not choose the redirection method then you have to think of another way, so the token solution is this way.

Just as the token itself represents permissions, the right to operate, identity, etc., so I can add such an identity flag for my form, when the client requests the form at the same time to generate a token of its hook, at the time of submission to judge, correct to receive and process the form. The realization of the essence is so, and reflected to the concrete implementation, you need to use a call session of things. For a session resolution, see the Wiki

The simple understanding is that the session is also a token concept, so you might be surprised, "What am I already using a token?" "Yes, but we're going to do more than just the session but attach some data to the form token we want to implement." So let ' s do it!

Session in PHP is also stored in the $_session of this super global variable, to enable the use of session_start (), for other server-side scripting principles, just may invoke method name inconsistencies. The code after adding token is as follows:

The code is as follows Copy Code
&lt;?php


Open session


Session_Start ();


if (Isset ($_post[' submit ')) &amp;&amp; Valid_token ()) {


Form





Submit Processing


}





/**


* Generate token


* @return String MD5 The time stamp after encryption


*/


function Create_token () {


Current time stamp





$timestamp = time ();


$_session[' token ' = $timestamp;


return MD5 ($TIMESTAMP);


}


/**


* Whether valid token


* @return BOOL








*/


function Valid_token () {


if (Isset ($_session[' token ')) &amp;&amp; isset ($_post[' token ']) &amp;&amp; $_post[' token '] = = MD5 (





$_session[' token '])


{


If the token is properly destroyed


$_session[' token '] = ';


return true;


}


return false;


}


?&gt;


&lt;?php if (isset ($state) &amp;&amp; $state) {//Data insertion Success?&gt;


&lt;p&gt; Insert Success &lt;a href= "form.php" &gt; Return





&lt;/a&gt;&lt;/p&gt;


&lt;?php} else {//failed or no Insert action?&gt;


&lt;form method= "POST" &gt;


&lt;p&gt;


&lt;label for= "Test" &gt; Casual





Enter a point what &lt;/label&gt;


&lt;input type= "text" name= "data" id= "test"/&gt;


&lt;/p&gt;


&lt;p&gt;


&lt;input type= "Submit" value= "mention





Pay "name=" Submit "/&gt;"


&lt;/p&gt;


&lt;/ul&gt;


&lt;!--Token--&gt;


&lt;input type= "hidden" value= "&lt;?php Echo Create_token (); Generated





Token?&gt; "name=" token "/&gt;


&lt;!--Token--&gt;


&lt;/form&gt;


&lt;?php}?&gt;

Part of the code Paperen here omitted, because it is not the point, actually add only 3 things:

First, add an INPUT element before the form ends, remember type is hidden (hidden field)

Second, add two functions, Create_token and Valid_token, which are used to generate tokens that are used to validate tokens

Third, add a condition to the IF, Valid_token

That's it, it's simple, and everything is clustered in two new functions. Paperen Here the token is very simple is the timestamp, the request form when the timestamp stored in the $_session[' token ', then the verification token is understood, is to check the client submitted $_post[' token ' after MD5 session[' token '] is consistent and, of course, there are two variables of $_post[' token ' and $_session[' token '.

You can encapsulate this simple token pattern in a much better way and extend the functionality, such as adding a form submission Timeout verification is a good hands-on opportunity.

Finally, attach the Form_validation class file of the previous Paperen extension codeingeter, mainly the extended token and the form timeout. The welcome.php in the compressed package is the controller file, please place it in the Applicationcontroller (if you do not want to increase the controller to open and then copy the token method to the existing other controller); my_form_ validation.php please put it in the applicationlibraries.

Codeingeter form_validation class file code

The code is as follows Copy Code

<?php if (! defined (' BasePath ')) exit (' No Direct script access allowed ');

Class Welcome extends Ci_controller {


Public Function Index ()
{
$this->load->view (' welcome_message ');
}

Public Function token ()


{


$this-&gt;load-&gt;helper (' form ');


$this-&gt;load-&gt;library (' form_validation ');


if ($this-&gt;input-&gt;post (' Submit ') &amp;&amp; $this-&gt;form_validation-&gt;valid_token ())


{


Nothing


Valid_token already contains token timeout and token correct judgment, to enable token timeout, set Token_validtime to non 0


echo ' OK ';


}

Generate Form Token
$token = $this->form_validation->create_token ();

form Example
Echo Form_Open ();
echo form_input (' token ', ');
Echo $token;
echo form_submit (' Submit ', ' submit ');
Echo Form_close ();
}
}

Form_validation_token

The code is as follows Copy Code

<?php if (! defined (' BasePath ')) exit (' No Direct script access allowed ');
/**
* @abstract the Form_validation class that inherits CI increases the token on its basis
*/
Class My_form_validation extends Ci_form_validation {

/**
* Token key value
* @var String
*/
var $key = ' token ';

/**
* Effective time of Form token (SEC)
* @abstract If some forms need to limit input time, set this value to 0 without limiting
* @var int seconds
*/
var $token _validtime = 5;

/**
* Debug Mode
* @var BOOL
*/
var $debug = false;

/**
* CI objects
* @var <type>
*/
Private $_ci;

Public Function __construct ()
{
Parent::__construct ();
$this->_ci =& get_instance ();
If the configuration is not filled in Encryption_key
$encryption _key = Config_item (' Encryption_key ');
if (Empty ($encryption _key)) $this->_ci->config->set_item (' Encryption_key ', $this->key);
If the session is not loaded
if (!isset ($this->_ci->session)) $this->_ci->load->library (' Session ');
}

/**
* Set token valid time
* @param int $second seconds
*/
Public Function Set_token_validtime ($second)
{
$this->token_validtime = intval ($second);
}

/**
* Get form token valid time
* @return int number of seconds
*/
Public Function Get_token_validtime ()
{
return $this->token_validtime;
}

   /**
     * Verifying that the form token is valid
     * @return bool
& nbsp;    */
    public Function Valid_token ()
    {
         if ($this->debug) return true;
       //Get hash in session
        $ Source_hash = $this->_ci->session->userdata ($this->key);
        if (empty ($source _hash)) return false;
       
       //Determine if timeout
         if ($this->is_token_exprie ()) return false;

The hash submitted
$post _formhash = $this->_ci->input->post ($this->key);
if (Empty ($post _formhash)) return false;

if (MD5 ($source _hash) = = $post _formhash)
{
$this->_ci->session->unset_userdata ($this->key);
return true;
}
return false;
}

/**


* Generate form token (along with INPUT element)


* @return String


*/


Public Function Create_token ($output = False)


{


$code = Time ().  '|' . $this-&gt;get_random (5);


$this-&gt;_ci-&gt;session-&gt;set_userdata ($this-&gt;key, $code);


$result = function_exists (' Form_hidden ')? Form_hidden ($this-&gt;key, MD5 ($code)): ' &lt;input type= ' hidden ' name= ' token ' value= '. MD5 ($code). '/&gt; ';


if ($output)


{


echo $result;


}


Else


{


return $result;


}


}





/**


* Get random number (you can extend it yourself)


* @param int $number Upper Limit


* @return String


*/


Public Function Get_random ($number)


{


Return rand (0, $number);


}





/**


* Determine if the form token is expired


* @return BOOL


*/


Public Function Is_token_exprie ()


{


if (Empty ($this-&gt;token_validtime)) return false;


$token = $this-&gt;_ci-&gt;session-&gt;userdata ($this-&gt;key);


if (empty ($token)) return false;


$create _time = array_shift (Explode (' | ', $token));


Return (Time ()-$create _time &gt; $this-&gt;token_validtime);


}


}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.