av手机免费在线观看,国产女人在线视频,国产xxxx免费,捆绑调教一二三区,97影院最新理论片,色之久久综合,国产精品日韩欧美一区二区三区

php語(yǔ)言

解決表單重復(fù)提交問(wèn)題的PHP代碼

時(shí)間:2025-04-08 18:35:38 php語(yǔ)言 我要投稿

解決表單重復(fù)提交問(wèn)題的PHP代碼

  如果學(xué)校不能在課堂中給予學(xué)生更多成功的體驗(yàn),他們就會(huì)以既在學(xué)校內(nèi)也在學(xué)校外都完全拒絕學(xué)習(xí)而告終。以下是小編為大家搜索整理的解決表單重復(fù)提交問(wèn)題的PHP代碼,希望對(duì)大家有所幫助!更多精彩內(nèi)容請(qǐng)及時(shí)關(guān)注我們應(yīng)屆畢業(yè)生考試網(wǎng)!

  以前用的js表單防止重復(fù)提交方法

 代碼如下  

<script type="text/javascript">
var checkSubmitFlg = false;
function checkSubmit() {
 if (!checkSubmitFlg) {

// 第一次提交
  checkSubmitFlg = true;
  return true;
 } else {

//重復(fù)提交
  alert("Submit again!");
  return false;
 }
}
</script>

//以下三種方式分別調(diào)用

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

<input type="submit" onclick="return checkSubmit();" />

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

  這樣如果我直接做一個(gè)表單,然后提交給/test,上面代理就是一個(gè)擺設(shè)了,那我們要如何解決此問(wèn)題

  如果您已經(jīng)知道如何解決的話那么這篇文章可能不適合你的口味,paperen這里也打算從基礎(chǔ)開(kāi)始討論,所以希望一步看到解決方案的您也可能不太適合,所以請(qǐng)注意。So~開(kāi)始吧 ~

  paperen想您一定知道表單是什么吧,form元素就是表單,一般網(wǎng)頁(yè)需要輸入的地方必定使用了表單元素,也很常見(jiàn),一般的代碼如下:

 代碼如下  

    <form
    
    method="post">
    <p>
    <label for="test">隨便輸入點(diǎn)什么www.45it.com</label>
    <input type="text" name="data" id="test" />
    </p>
    <p>
    <input type="submit" value="提交" name="submit" />
    </p>
    </ul>
    </form>

  重點(diǎn)其實(shí)是form與input元素,p元素只是paperen私自加上去的,對(duì)后續(xù)的說(shuō)明沒(méi)有任何影響,其實(shí)很簡(jiǎn)單,所謂input就是輸入了,你可以完全將input 元素理解為是用作用戶輸入,只是某些屬性的(type)不能作為輸入而已(這里就是submit),而form元素你完全可以將它理解為是一個(gè)袋子,將所有用戶輸入數(shù)據(jù)到裝在它里面之后用 來(lái)提交回服務(wù)端處理,但對(duì)于form元素值得注意的是method屬性,一般來(lái)說(shuō)有g(shù)et與post兩種方法,其實(shí)不要想得太復(fù)雜(因?yàn)樯钊氲牟恍枰斫猓瑢?duì)于后續(xù)的內(nèi)容沒(méi)有太多關(guān)系,如 有興趣不妨可以使用瀏覽器的調(diào)試工具查看請(qǐng)求頭部信息與發(fā)送信息,例如firebug),表現(xiàn)出來(lái)就是,使用get提交表單的話所有的input元素的值將會(huì)在地址欄處出現(xiàn),而post則不會(huì), 例如使用get提交此表單后的瀏覽器地址欄

 代碼如下  

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

  post則在 地址欄看不到了,使用fiebug可以看到如下信息

  可以簡(jiǎn)單認(rèn)為get是顯式傳送數(shù)據(jù)的,而 post則是隱式傳送數(shù)據(jù)的,但還有一個(gè)很大區(qū)別的是post支持更多更大的數(shù)據(jù)傳送。

  Next,當(dāng)表單代碼寫(xiě)好了,那么讓我們來(lái)進(jìn)行服務(wù)器腳本的編寫(xiě)(這里就是PHP)。很簡(jiǎn)單 ~

 代碼如下  
<?php
    if ( isset( $_POST['submit'] ) ) {
    //表單提交處理
    $data = isset( $_POST['data'] ) ? htmlspecialchars( $_POST['data'] ) :
    
    '';
    //Insert or Update數(shù)據(jù)庫(kù)
    $sql = "insert into test (`string`) values ('$data')";
    //do query
    echo $sql;
    }
    ?>

  因?yàn)檫@里是post傳送數(shù)據(jù)的,所以使用PHP的$_POST全局變量就能獲取到表單提交的數(shù)據(jù),所有使用post方法的表單數(shù)據(jù)提交到服務(wù)端都會(huì)被保存在這個(gè)$_POST全局變 量中,不妨可以試試print_r( $_POST )這個(gè)變量你就明白了。

  首先檢查一下是否在$_POST數(shù)組里面存在submit,如果存在則證明是表單提交過(guò)來(lái)的,正如asp.net中好像有個(gè) 叫ispostback的一樣,只是這樣沒(méi)那么嚴(yán)謹(jǐn)而已,但是不要緊之后會(huì)解決這個(gè)問(wèn)題的。

  之后接收輸入框的數(shù)據(jù),就是$_POST['data'],別忘了使用htmlspecialchars對(duì)這個(gè)進(jìn) 行一下html過(guò)濾,因?yàn)榉乐馆斎肓薶tml標(biāo)簽或javascript造成問(wèn)題(貌似叫做XSS漏洞)。最后就是拼接到sql語(yǔ)句中送入數(shù)據(jù)庫(kù)跑了(只是這里paperen并沒(méi)有很詳細(xì)使用一些操作數(shù)據(jù)庫(kù)的 函數(shù)例如mysql_query,有興趣自己完成它)。恭喜,到了這里你已經(jīng)順利地完成了一個(gè)數(shù)據(jù)錄入的功能了,但是有個(gè)地方你總得改善吧,插入數(shù)據(jù)后總得給操作者一個(gè)提示吧~~至少提示 我操作失敗還是成功。所以整個(gè)代碼paperen寫(xiě)成以下樣子。

 代碼如下  

<?php
    if ( isset( $_POST['submit'] ) ) {
    //表單提交處理
    $data = isset(
    
    $_POST['data'] ) ? htmlspecialchars( $_POST['data'] ) : '';
    //connect
    mysql_connect( 'localhost', 'root', 'root' );
    
    //select db
    mysql_select_db( 'test' );
    //設(shè)置字符集防止亂碼
    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;
    }
    }
    ?>

    <?php if ( isset( $state )

    && $state ) { //數(shù)據(jù)插入成功 ?>

    <p>插入成功 <a href="form.php">返回</a></p>

    <?php } else { //失敗或者沒(méi)有插入動(dòng)

    作 ?>

    <form method="post">

    <p>

    <label for="test">隨便輸入點(diǎn)什么</label>

    <input type="text"

    name="data" id="test" />

    </p>

    <p>

    <input type="submit" value="提交" name="submit" />

    </p>

    </ul>

    </form>

    <?php } ?>

  html的聲明與head還有body都省略了,對(duì)比于一開(kāi)始的代碼其實(shí)主要是實(shí)現(xiàn)了真正插入數(shù)據(jù)庫(kù)動(dòng)作與給出 了操作反饋(通過(guò)$state變量),不妨自己拷貝代碼然后試試(當(dāng)然請(qǐng)根據(jù)自己實(shí)際情況修改數(shù)據(jù)庫(kù)操作部分的代碼)。代碼正常,邏輯沒(méi)問(wèn)題,但是有個(gè)問(wèn)題,就是在顯示插入成功后再刷新頁(yè) 面又會(huì)執(zhí)行了表單處理動(dòng)作,又插了一遍數(shù)據(jù)!這就是所謂的重復(fù)插入問(wèn)題。在放出解決方案之前您可以自己思考一下該如何解決。

  你會(huì)不會(huì)認(rèn)為是接收數(shù)據(jù)與顯示處理結(jié)果都是 這個(gè)頁(yè)面所以才會(huì)導(dǎo)致這個(gè)問(wèn)題?也對(duì),也可以這么認(rèn)為,使用一些調(diào)試工具你會(huì)發(fā)現(xiàn),瀏覽器還對(duì)post的數(shù)據(jù)進(jìn)行了保留,故在提交完表單后再刷新的話該post數(shù)據(jù)會(huì)重新提交了一遍。

  如果有辦法將瀏覽器的這個(gè)臨時(shí)保存的post數(shù)據(jù)清空掉不就解決問(wèn)題了,但服務(wù)端是沒(méi)法 做到這點(diǎn)的,因?yàn)檫@是瀏覽器自身的事情,要么我們就重定向了不然再刷新還是會(huì)重復(fù)提交數(shù)據(jù)。

  到目前為止也許你已經(jīng)了解到重復(fù)提交的意思與問(wèn)題的惡劣所在,如果 你不是選用重定向的辦法那么就得另外想一個(gè)辦法了,所以令牌解決辦法就是這么過(guò)來(lái)的。

  正如令牌本身代表著權(quán)限,操作權(quán),身份標(biāo)志等等,所以我能不能為我的表單加上這么 一個(gè)身份標(biāo)志,在客戶端每次請(qǐng)求這個(gè)表單的時(shí)候同時(shí)生成一個(gè)令牌其掛鉤,在提交時(shí)再進(jìn)行判斷,正確則接收并處理表單。實(shí)現(xiàn)本質(zhì)就是如此,而反映到具體實(shí)現(xiàn)上,就需要用到一種叫 session的東西。關(guān)于session的解析,參見(jiàn)wiki

  簡(jiǎn)單的理解就是session也是一種令 牌的概念,所以你可能會(huì)很驚奇,“什么我已經(jīng)使用了令牌?!”,是的,但是我們要實(shí)現(xiàn)的不僅僅是session而是在其基礎(chǔ)上附加一些數(shù)據(jù)來(lái)實(shí)現(xiàn)我們想要的表單令牌。So let's do it!

  session在php中也是被存放在$_SESSION這個(gè)超級(jí)全局變量里面的,啟用起請(qǐng)使用session_start(),關(guān)于其他服務(wù)端腳本原理一樣,只是可能調(diào)用方法名不一致而已。加入 token后的代碼如下:

 代碼如下  
   <?php
    //開(kāi)啟session
    session_start();
    if ( isset( $_POST['submit'] ) && valid_token() ) {
    //表單
    
    提交處理
    }
    
    /**
    * 生成令牌
    * @return string MD5加密后的時(shí)間戳
    */
    function create_token() {
    //當(dāng)前時(shí)間戳
    
    $timestamp = time();
    $_SESSION['token'] = $timestamp;
    return md5( $timestamp );
    }
    /**
    * 是否有效令牌
    * @return bool
    
    
    */
    function valid_token() {
    if ( isset( $_SESSION['token'] ) && isset( $_POST['token'] ) && $_POST['token'] == md5(
    
    $_SESSION['token'] ) )
    {
    //若正確將本次令牌銷(xiāo)毀掉
    $_SESSION['token'] = '';
    return true;
    }
    return false;
    }
    ?>
    <?php if ( isset( $state ) && $state ) { //數(shù)據(jù)插入成功 ?>
    <p>插入成功 <a href="form.php">返回
    
    </a></p>
    <?php } else { //失敗或者沒(méi)有插入動(dòng)作 ?>
    <form method="post">
    <p>
    <label for="test">隨便
    
    輸入點(diǎn)什么</label>
    <input type="text" name="data" id="test" />
    </p>
    <p>
    <input type="submit" value="提
    
    交" name="submit" />
    </p>
    </ul>
    <!-- Token -->
    <input type="hidden" value="<?php echo create_token(); //生成
    
    令牌 ?>" name="token" />
    <!-- Token -->
    </form>
    <?php } ?>

  部分代碼paperen這里省略,因?yàn)椴⒉皇侵攸c(diǎn),其實(shí)加的 東西只有3處:

  第一,在表單結(jié)束前加入了一個(gè)input元素,記得type為hidden(隱藏域)

  第二,增加了兩個(gè)函數(shù),create_token與valid_token,前者用來(lái)生成令牌 的后者用來(lái)驗(yàn)證令牌的

  第三,在if中多加一個(gè)條件,valid_token

  那就大功告成了,很簡(jiǎn)單,而且所有的東西都聚集在新加的兩個(gè)函數(shù)中。paperen這里使用的令牌很 簡(jiǎn)單就是時(shí)間戳,將請(qǐng)求表單時(shí)的時(shí)間戳存儲(chǔ)到$_SESSION['token']中,那么驗(yàn)證令牌就明白了,就是檢查客戶端提交過(guò)來(lái)的$_POST['token']是否與md5后的$_SESSION['token']一致 就行了,當(dāng)然還要加上存在$_POST['token']與$_SESSION['token']這兩個(gè)變量才行。

  你可以將這個(gè)簡(jiǎn)單的令牌模式封裝得更加棒并擴(kuò)展一下功能,例如加上表單提交超時(shí)驗(yàn)證 也是個(gè)不錯(cuò)的動(dòng)手機(jī)會(huì)。

  最后附上之前paperen擴(kuò)展codeingeter的Form_validation類(lèi)文件,主要是擴(kuò)展上令牌與表單超時(shí)。壓縮包中welcome.php是控制器文件,請(qǐng)放置到 applicationcontroller中(如不想增加這個(gè)控制器可以打開(kāi)然后將token方法復(fù)制下來(lái)放到已有的其他控制器中);MY_Form_validation.php請(qǐng)放到applicationlibraries中。

  codeingeter的Form_validation類(lèi)文件代碼

 代碼如下  

<?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->load->helper( array('form') );
            $this->load->library('form_validation');
            if ( $this->input->post( 'submit' ) && $this->form_validation->valid_token() )
            {
                //nothing
                //valid_token已經(jīng)包含令牌超時(shí)與令牌正確的判斷,若要啟用令牌超時(shí),請(qǐng)將token_validtime設(shè)置為非0
                echo 'ok';
            }

            //生成表單令牌
            $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

 代碼如下  

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * @abstract 繼承CI的Form_validation類(lèi)在其基礎(chǔ)上增加令牌
 */
class MY_Form_validation extends CI_Form_validation {

    /**
     * 令牌鍵值
     * @var string
     */
    var $key = 'token';
   
    /**
     * 表單令牌有效時(shí)間(秒)
     * @abstract 如果某些表單需要限制輸入時(shí)間,則設(shè)置該值,為0則不限制
     * @var int 秒
     */
    var $token_validtime = 5;

    /**
     * 調(diào)試模式
     * @var bool
     */
    var $debug = false;

    /**
     * CI對(duì)象
     * @var <type>
     */
    private $_CI;

    public function __construct()
    {
        parent::__construct();
        $this->_CI =& get_instance();
        //如果配置沒(méi)有填寫(xiě)encryption_key
        $encryption_key = config_item('encryption_key');
        if ( empty( $encryption_key ) ) $this->_CI->config->set_item( 'encryption_key', $this->key );
        //如果沒(méi)有裝載session
        if ( !isset( $this->_CI->session ) ) $this->_CI->load->library('session');
    }

    /**
     * 設(shè)置令牌有效時(shí)間
     * @param int $second 秒數(shù)
     */
    public function set_token_validtime( $second )
    {
        $this->token_validtime = intval( $second );
    }

    /**
     * 獲取表單令牌有效時(shí)間
     * @return int 秒數(shù)
     */
    public function get_token_validtime()
    {
        return $this->token_validtime;
    }

    /**
     * 驗(yàn)證表單令牌是否合法
     * @return bool
     */
    public function valid_token()
    {
        if ( $this->debug ) return true;
        //獲取session中的hash
        $source_hash = $this->_CI->session->userdata( $this->key );
        if ( empty( $source_hash ) ) return false;
       
        //判斷是否超時(shí)
        if ( $this->is_token_exprie() ) return false;

        //提交的hash
        $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;
    }

    /**
     * 生成表單令牌(連同input元素)
     * @return string
     */
    public function create_token( $output = false )
    {
        $code = time() . '|' .  $this->get_random( 5 );
        $this->_CI->session->set_userdata( $this->key , $code);
        $result = function_exists('form_hidden') ? form_hidden( $this->key, md5( $code ) ) : '<input type="hidden" name="token" value="'. md5( $code ) .'" />';
        if ( $output )
        {
            echo $result;
        }
        else
        {
            return $result;
        }
    }
   
    /**
     * 獲取隨機(jī)數(shù)(自己可以擴(kuò)展)
     * @param int $number 上限
     * @return string
     */
    public function get_random( $number )
    {
        return rand( 0, $number );
    }
   
    /**
     * 判斷表單令牌是否過(guò)期
     * @return bool
     */
    public function is_token_exprie()
    {
        if ( empty( $this->token_validtime ) ) return false;
        $token = $this->_CI->session->userdata( $this->key );
        if ( empty( $token ) ) return false;
        $create_time = array_shift( explode('|', $token) );
        return ( time() - $create_time > $this->token_validtime );
    }
}


【解決表單重復(fù)提交問(wèn)題的PHP代碼】相關(guān)文章:

如何真正解決表單重復(fù)提交問(wèn)題php代碼10-11

php防止表單重復(fù)提交的方法10-16

如何讓php提交form表單11-06

PHP提交from表單的方法07-05

php通過(guò)記錄IP來(lái)防止表單重復(fù)提交方法分析10-17

使用php自動(dòng)提交表單的方法11-16

php提交form表單處理方法07-12

php表單提交與$-POST實(shí)例分析11-15

用PHP提交from表單的處理方法09-06