<delect id="sj01t"></delect>
  1. <em id="sj01t"><label id="sj01t"></label></em>
  2. <div id="sj01t"></div>
    1. <em id="sj01t"></em>

            <div id="sj01t"></div>
            php語言

            解決表單重復提交問題的PHP代碼

            時間:2025-04-08 18:35:38 php語言 我要投稿

            解決表單重復提交問題的PHP代碼

              如果學校不能在課堂中給予學生更多成功的體驗,他們就會以既在學校內也在學校外都完全拒絕學習而告終。以下是小編為大家搜索整理的解決表單重復提交問題的PHP代碼,希望對大家有所幫助!更多精彩內容請及時關注我們應屆畢業生考試網!

              以前用的js表單防止重復提交方法

             代碼如下  

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

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

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

            //以下三種方式分別調用

            <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();" />

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

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

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

             代碼如下  

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

              重點其實是form與input元素,p元素只是paperen私自加上去的,對后續的說明沒有任何影響,其實很簡單,所謂input就是輸入了,你可以完全將input 元素理解為是用作用戶輸入,只是某些屬性的(type)不能作為輸入而已(這里就是submit),而form元素你完全可以將它理解為是一個袋子,將所有用戶輸入數據到裝在它里面之后用 來提交回服務端處理,但對于form元素值得注意的是method屬性,一般來說有get與post兩種方法,其實不要想得太復雜(因為深入的不需要太理解,對于后續的內容沒有太多關系,如 有興趣不妨可以使用瀏覽器的調試工具查看請求頭部信息與發送信息,例如firebug),表現出來就是,使用get提交表單的話所有的input元素的值將會在地址欄處出現,而post則不會, 例如使用get提交此表單后的瀏覽器地址欄

             代碼如下  

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

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

              可以簡單認為get是顯式傳送數據的,而 post則是隱式傳送數據的,但還有一個很大區別的是post支持更多更大的數據傳送。

              Next,當表單代碼寫好了,那么讓我們來進行服務器腳本的編寫(這里就是PHP)。很簡單 ~

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

              因為這里是post傳送數據的,所以使用PHP的$_POST全局變量就能獲取到表單提交的數據,所有使用post方法的表單數據提交到服務端都會被保存在這個$_POST全局變 量中,不妨可以試試print_r( $_POST )這個變量你就明白了。

              首先檢查一下是否在$_POST數組里面存在submit,如果存在則證明是表單提交過來的,正如asp.net中好像有個 叫ispostback的一樣,只是這樣沒那么嚴謹而已,但是不要緊之后會解決這個問題的。

              之后接收輸入框的數據,就是$_POST['data'],別忘了使用htmlspecialchars對這個進 行一下html過濾,因為防止輸入了html標簽或javascript造成問題(貌似叫做XSS漏洞)。最后就是拼接到sql語句中送入數據庫跑了(只是這里paperen并沒有很詳細使用一些操作數據庫的 函數例如mysql_query,有興趣自己完成它)。恭喜,到了這里你已經順利地完成了一個數據錄入的功能了,但是有個地方你總得改善吧,插入數據后總得給操作者一個提示吧~~至少提示 我操作失敗還是成功。所以整個代碼paperen寫成以下樣子。

             代碼如下  

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

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

                <?php } else { //失敗或者沒有插入動

                作 ?>

                <form method="post">

                <p>

                <label for="test">隨便輸入點什么</label>

                <input type="text"

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

                </p>

                <p>

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

                </p>

                </ul>

                </form>

                <?php } ?>

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

              你會不會認為是接收數據與顯示處理結果都是 這個頁面所以才會導致這個問題?也對,也可以這么認為,使用一些調試工具你會發現,瀏覽器還對post的數據進行了保留,故在提交完表單后再刷新的話該post數據會重新提交了一遍。

              如果有辦法將瀏覽器的這個臨時保存的post數據清空掉不就解決問題了,但服務端是沒法 做到這點的,因為這是瀏覽器自身的事情,要么我們就重定向了不然再刷新還是會重復提交數據。

              到目前為止也許你已經了解到重復提交的意思與問題的惡劣所在,如果 你不是選用重定向的辦法那么就得另外想一個辦法了,所以令牌解決辦法就是這么過來的。

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

              簡單的理解就是session也是一種令 牌的概念,所以你可能會很驚奇,“什么我已經使用了令牌?!”,是的,但是我們要實現的不僅僅是session而是在其基礎上附加一些數據來實現我們想要的表單令牌。So let's do it!

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

             代碼如下  
               <?php
                //開啟session
                session_start();
                if ( isset( $_POST['submit'] ) && valid_token() ) {
                //表單
                
                提交處理
                }
                
                /**
                * 生成令牌
                * @return string MD5加密后的時間戳
                */
                function create_token() {
                //當前時間戳
                
                $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'] ) )
                {
                //若正確將本次令牌銷毀掉
                $_SESSION['token'] = '';
                return true;
                }
                return false;
                }
                ?>
                <?php if ( isset( $state ) && $state ) { //數據插入成功 ?>
                <p>插入成功 <a href="form.php">返回
                
                </a></p>
                <?php } else { //失敗或者沒有插入動作 ?>
                <form method="post">
                <p>
                <label for="test">隨便
                
                輸入點什么</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這里省略,因為并不是重點,其實加的 東西只有3處:

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

              第二,增加了兩個函數,create_token與valid_token,前者用來生成令牌 的后者用來驗證令牌的

              第三,在if中多加一個條件,valid_token

              那就大功告成了,很簡單,而且所有的東西都聚集在新加的兩個函數中。paperen這里使用的令牌很 簡單就是時間戳,將請求表單時的時間戳存儲到$_SESSION['token']中,那么驗證令牌就明白了,就是檢查客戶端提交過來的$_POST['token']是否與md5后的$_SESSION['token']一致 就行了,當然還要加上存在$_POST['token']與$_SESSION['token']這兩個變量才行。

              你可以將這個簡單的令牌模式封裝得更加棒并擴展一下功能,例如加上表單提交超時驗證 也是個不錯的動手機會。

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

              codeingeter的Form_validation類文件代碼

             代碼如下  

            <?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已經包含令牌超時與令牌正確的判斷,若要啟用令牌超時,請將token_validtime設置為非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類在其基礎上增加令牌
             */
            class MY_Form_validation extends CI_Form_validation {

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

                /**
                 * 調試模式
                 * @var bool
                 */
                var $debug = false;

                /**
                 * CI對象
                 * @var <type>
                 */
                private $_CI;

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

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

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

                /**
                 * 驗證表單令牌是否合法
                 * @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;
                   
                    //判斷是否超時
                    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;
                    }
                }
               
                /**
                 * 獲取隨機數(自己可以擴展)
                 * @param int $number 上限
                 * @return string
                 */
                public function get_random( $number )
                {
                    return rand( 0, $number );
                }
               
                /**
                 * 判斷表單令牌是否過期
                 * @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 );
                }
            }


            【解決表單重復提交問題的PHP代碼】相關文章:

            如何真正解決表單重復提交問題php代碼10-11

            php防止表單重復提交的方法10-16

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

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

            php通過記錄IP來防止表單重復提交方法分析10-17

            使用php自動提交表單的方法11-16

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

            php表單提交與$-POST實例分析11-15

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

            <delect id="sj01t"></delect>
            1. <em id="sj01t"><label id="sj01t"></label></em>
            2. <div id="sj01t"></div>
              1. <em id="sj01t"></em>

                      <div id="sj01t"></div>
                      黄色视频在线观看