- 相關(guān)推薦
如何真正解決表單重復(fù)提交問題php代碼
過去一切時代的精華盡在書中。以下是小編為大家搜索整理的如何真正解決表單重復(fù)提交問題php代碼,希望能給大家?guī)韼椭?更多精彩內(nèi)容請及時關(guān)注我們應(yīng)屆畢業(yè)生考試網(wǎng)!
以前用的js表單防止重復(fù)提交方法
代碼如下 | |
<script type="text/javascript">
// 第一次提交
//重復(fù)提交 //以下三種方式分別調(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();" /> |
這樣如果我直接做一個表單,然后提交給/test,上面代理就是一個擺設(shè)了,那我們要如何解決此問題
如果您已經(jīng)知道如何解決的話那么這篇文章可能不適合你的口味,paperen這里也打算從基礎(chǔ)開始討論,所以希望一步看到解決方案的您也可能不太適合,所以請注意。So~開始吧 ~
paperen想您一定知道表單是什么吧,form元素就是表單,一般網(wǎng)頁需要輸入的地方必定使用了表單元素,也很常見,一般的代碼如下:
代碼如下 | |
<form |
重點其實是form與input元素,p元素只是paperen私自加上去的,對后續(xù)的說明沒有任何影響,其實很簡單,所謂input就是輸入了,你可以完全將input 元素理解為是用作用戶輸入,只是某些屬性的(type)不能作為輸入而已(這里就是submit),而form元素你完全可以將它理解為是一個袋子,將所有用戶輸入數(shù)據(jù)到裝在它里面之后用 來提交回服務(wù)端處理,但對于form元素值得注意的是method屬性,一般來說有g(shù)et與post兩種方法,其實不要想得太復(fù)雜(因為深入的不需要太理解,對于后續(xù)的內(nèi)容沒有太多關(guān)系,如 有興趣不妨可以使用瀏覽器的調(diào)試工具查看請求頭部信息與發(fā)送信息,例如firebug),表現(xiàn)出來就是,使用get提交表單的話所有的input元素的值將會在地址欄處出現(xiàn),而post則不會, 例如使用get提交此表單后的瀏覽器地址欄
代碼如下 | |
http://localhost/mytest/token/form.php?data=test&submit=%E6%8F%90%E4%BA%A4 |
post則在 地址欄看不到了,使用fiebug可以看到如下信息
可以簡單認為get是顯式傳送數(shù)據(jù)的,而 post則是隱式傳送數(shù)據(jù)的,但還有一個很大區(qū)別的是post支持更多更大的數(shù)據(jù)傳送。
Next,當表單代碼寫好了,那么讓我們來進行服務(wù)器腳本的編寫(這里就是PHP)。很簡單 ~
代碼如下 | |
<?php if ( isset( $_POST['submit'] ) ) { //表單提交處理 $data = isset( $_POST['data'] ) ? htmlspecialchars( $_POST['data'] ) : ''; //Insert or Update數(shù)據(jù)庫 $sql = "insert into test (`string`) values ('$data')"; //do query echo $sql; } ?> |
因為這里是post傳送數(shù)據(jù)的,所以使用PHP的$_POST全局變量就能獲取到表單提交的數(shù)據(jù),所有使用post方法的表單數(shù)據(jù)提交到服務(wù)端都會被保存在這個$_POST全局變 量中,不妨可以試試print_r( $_POST )這個變量你就明白了。
首先檢查一下是否在$_POST數(shù)組里面存在submit,如果存在則證明是表單提交過來的,正如asp.net中好像有個 叫ispostback的一樣,只是這樣沒那么嚴謹而已,但是不要緊之后會解決這個問題的。
之后接收輸入框的數(shù)據(jù),就是$_POST['data'],別忘了使用htmlspecialchars對這個進 行一下html過濾,因為防止輸入了html標簽或javascript造成問題(貌似叫做XSS漏洞)。最后就是拼接到sql語句中送入數(shù)據(jù)庫跑了(只是這里paperen并沒有很詳細使用一些操作數(shù)據(jù)庫的 函數(shù)例如mysql_query,有興趣自己完成它)。恭喜,到了這里你已經(jīng)順利地完成了一個數(shù)據(jù)錄入的功能了,但是有個地方你總得改善吧,插入數(shù)據(jù)后總得給操作者一個提示吧~~至少提示 我操作失敗還是成功。所以整個代碼paperen寫成以下樣子。
代碼如下 | |
<?php <?php if ( isset( $state ) && $state ) { //數(shù)據(jù)插入成功 ?> <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都省略了,對比于一開始的代碼其實主要是實現(xiàn)了真正插入數(shù)據(jù)庫動作與給出 了操作反饋(通過$state變量),不妨自己拷貝代碼然后試試(當然請根據(jù)自己實際情況修改數(shù)據(jù)庫操作部分的代碼)。代碼正常,邏輯沒問題,但是有個問題,就是在顯示插入成功后再刷新頁 面又會執(zhí)行了表單處理動作,又插了一遍數(shù)據(jù)!這就是所謂的重復(fù)插入問題。在放出解決方案之前您可以自己思考一下該如何解決。
你會不會認為是接收數(shù)據(jù)與顯示處理結(jié)果都是 這個頁面所以才會導(dǎo)致這個問題?也對,也可以這么認為,使用一些調(diào)試工具你會發(fā)現(xiàn),瀏覽器還對post的數(shù)據(jù)進行了保留,故在提交完表單后再刷新的話該post數(shù)據(jù)會重新提交了一遍。
如果有辦法將瀏覽器的這個臨時保存的post數(shù)據(jù)清空掉不就解決問題了,但服務(wù)端是沒法 做到這點的,因為這是瀏覽器自身的事情,要么我們就重定向了不然再刷新還是會重復(fù)提交數(shù)據(jù)。
到目前為止也許你已經(jīng)了解到重復(fù)提交的意思與問題的惡劣所在,如果 你不是選用重定向的辦法那么就得另外想一個辦法了,所以令牌解決辦法就是這么過來的。
正如令牌本身代表著權(quán)限,操作權(quán),身份標志等等,所以我能不能為我的表單加上這么 一個身份標志,在客戶端每次請求這個表單的時候同時生成一個令牌其掛鉤,在提交時再進行判斷,正確則接收并處理表單。實現(xiàn)本質(zhì)就是如此,而反映到具體實現(xiàn)上,就需要用到一種叫 session的東西。關(guān)于session的解析,參見wiki
簡單的理解就是session也是一種令 牌的概念,所以你可能會很驚奇,“什么我已經(jīng)使用了令牌?!”,是的,但是我們要實現(xiàn)的不僅僅是session而是在其基礎(chǔ)上附加一些數(shù)據(jù)來實現(xiàn)我們想要的表單令牌。So let's do it!
session在php中也是被存放在$_SESSION這個超級全局變量里面的,啟用起請使用session_start(),關(guān)于其他服務(wù)端腳本原理一樣,只是可能調(diào)用方法名不一致而已。加入 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 ) { //數(shù)據(jù)插入成功 ?> <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處:
第一,在表單結(jié)束前加入了一個input元素,記得type為hidden(隱藏域)
第二,增加了兩個函數(shù),create_token與valid_token,前者用來生成令牌 的后者用來驗證令牌的
第三,在if中多加一個條件,valid_token
那就大功告成了,很簡單,而且所有的東西都聚集在新加的兩個函數(shù)中。paperen這里使用的令牌很 簡單就是時間戳,將請求表單時的時間戳存儲到$_SESSION['token']中,那么驗證令牌就明白了,就是檢查客戶端提交過來的$_POST['token']是否與md5后的$_SESSION['token']一致 就行了,當然還要加上存在$_POST['token']與$_SESSION['token']這兩個變量才行。
你可以將這個簡單的令牌模式封裝得更加棒并擴展一下功能,例如加上表單提交超時驗證 也是個不錯的動手機會。
最后附上之前paperen擴展codeingeter的Form_validation類文件,主要是擴展上令牌與表單超時。壓縮包中welcome.php是控制器文件,請放置到 applicationcontroller中(如不想增加這個控制器可以打開然后將token方法復(fù)制下來放到已有的其他控制器中);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 token()
//生成表單令牌
//form example |
form_validation_token
代碼如下 | |
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
/**
/**
public function __construct()
/**
/**
/**
//提交的hash
if ( md5( $source_hash ) == $post_formhash )
/** |
【如何真正解決表單重復(fù)提交問題php代碼】相關(guān)文章:
php通過記錄IP來防止表單重復(fù)提交方法分析10-17
如何實現(xiàn)php登陸表單提交CSRF及驗證碼09-14
如何實現(xiàn)PHP獲取表單數(shù)據(jù)與HTML嵌入PHP腳本09-23
完美解決PHP中文亂碼問題07-18
php語言字典代碼06-08
如何利用PHP時間轉(zhuǎn)換Unix時間戳代碼10-21
php下載代碼怎么寫07-13
PHP源代碼方式詳解08-08