찾다
백엔드 개발PHP 튜토리얼真正解决表单重复提交问题php代码_PHP教程

真正解决表单重复提交问题php代码_PHP教程

Jul 13, 2016 am 10:47 AM
jqueryphp암호제출하다프로그램형태해결하다반복하다질문예방하다

以前看过很多各种防止表单重复提交js或jquery程序,但这种只是一个简单的方法,如果我们不从这个页面提交表单,直接找到接受数据的页面这种js处理方法就无效了,下面我利用php一些方法来解决。

以前用的js表单防止重复提交方法

 代码如下 复制代码

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

//重复提交
  alert("Submit again!");
  return false;
 }
}

//以下三种方式分别调用

这样如果我直接做一个表单,然后提交给/test,上面代理就是一个摆设了,那我们要如何解决此问题

如果您已经知道如何解决的话那么这篇文章可能不适合你的口味,paperen这里也打算从基础开始讨论,所以希望一步看到解决方案的您也可能不太适合,所以请注意。So~开始吧 ~

paperen想您一定知道表单是什么吧,form元素就是表单,一般网页需要输入的地方必定使用了表单元素,也很常见,一般的代码如下:

 代码如下 复制代码

   

    
    method="post">
   


   
   
   


   


   
   


   
   

重点其实是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)。很简单 ~

   

 代码如下 复制代码
    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写成以下样子。

   

 代码如下 复制代码

    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;
    }
    }
    ?>

   

    && $state ) { //数据插入成功 ?>

   

插入成功 返回

   

    作 ?>

   

   

   

   

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

   

   

   

   

   

   

   

html的声明与head还有body都省略了,对比于一开始的代码其实主要是实现了真正插入数据库动作与给出 了操作反馈(通过$state变量),不妨自己拷贝代码然后试试(当然请根据自己实际情况修改数据库操作部分的代码)。代码正常,逻辑没问题,但是有个问题,就是在显示插入成功后再刷新页 面又会执行了表单处理动作,又插了一遍数据!这就是所谓的重复插入问题。在放出解决方案之前您可以自己思考一下该如何解决。

你会不会认为是接收数据与显示处理结果都是 这个页面所以才会导致这个问题?也对,也可以这么认为,使用一些调试工具你会发现,浏览器还对post的数据进行了保留,故在提交完表单后再刷新的话该post数据会重新提交了一遍。

如果有办法将浏览器的这个临时保存的post数据清空掉不就解决问题了,但服务端是没法 做到这点的,因为这是浏览器自身的事情,要么我们就重定向了不然再刷新还是会重复提交数据。

到目前为止也许你已经了解到重复提交的意思与问题的恶劣所在,如果 你不是选用重定向的办法那么就得另外想一个办法了,所以令牌解决办法就是这么过来的。

正如令牌本身代表着权限,操作权,身份标志等等,所以我能不能为我的表单加上这么 一个身份标志,在客户端每次请求这个表单的时候同时生成一个令牌其挂钩,在提交时再进行判断,正确则接收并处理表单。实现本质就是如此,而反映到具体实现上,就需要用到一种叫 session的东西。关于session的解析,参见wiki

简单的理解就是session也是一种令 牌的概念,所以你可能会很惊奇,“什么我已经使用了令牌?!”,是的,但是我们要实现的不仅仅是session而是在其基础上附加一些数据来实现我们想要的表单令牌。So let's do it!

session在php中也是被存放在$_SESSION这个超级全局变量里面的,启用起请使用session_start(),关于其他服务端脚本原理一样,只是可能调用方法名不一致而已。加入 token后的代码如下:

 

 代码如下 复制代码
       //开启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;
    }
    ?>
   
   

插入成功 返回
    
   


   
   

   


   
   
   


   


   
   


   
   
   
   
   

   

部分代码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类文件代码

 代码如下 复制代码

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

 代码如下 复制代码

/**
 * @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
     */
    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 ) ) : '';
        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 );
    }
}

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/632826.htmlTechArticle以前看过很多各种防止表单重复提交js或jquery程序,但这种只是一个简单的方法,如果我们不从这个页面提交表单,直接找到接受数据的页面...
성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
PHP : 서버 측 스크립팅 언어 소개PHP : 서버 측 스크립팅 언어 소개Apr 16, 2025 am 12:18 AM

PHP는 동적 웹 개발 및 서버 측 응용 프로그램에 사용되는 서버 측 스크립팅 언어입니다. 1.PHP는 편집이 필요하지 않으며 빠른 발전에 적합한 해석 된 언어입니다. 2. PHP 코드는 HTML에 포함되어 웹 페이지를 쉽게 개발할 수 있습니다. 3. PHP는 서버 측 로직을 처리하고 HTML 출력을 생성하며 사용자 상호 작용 및 데이터 처리를 지원합니다. 4. PHP는 데이터베이스와 상호 작용하고 프로세스 양식 제출 및 서버 측 작업을 실행할 수 있습니다.

PHP 및 웹 : 장기적인 영향 탐색PHP 및 웹 : 장기적인 영향 탐색Apr 16, 2025 am 12:17 AM

PHP는 지난 수십 년 동안 네트워크를 형성했으며 웹 개발에서 계속 중요한 역할을 할 것입니다. 1) PHP는 1994 년에 시작되었으며 MySQL과의 원활한 통합으로 인해 개발자에게 최초의 선택이되었습니다. 2) 핵심 기능에는 동적 컨텐츠 생성 및 데이터베이스와의 통합이 포함되며 웹 사이트를 실시간으로 업데이트하고 맞춤형 방식으로 표시 할 수 있습니다. 3) PHP의 광범위한 응용 및 생태계는 장기적인 영향을 미쳤지 만 버전 업데이트 및 보안 문제에 직면 해 있습니다. 4) PHP7의 출시와 같은 최근 몇 년간의 성능 향상을 통해 현대 언어와 경쟁 할 수 있습니다. 5) 앞으로 PHP는 컨테이너화 및 마이크로 서비스와 같은 새로운 도전을 다루어야하지만 유연성과 활발한 커뮤니티로 인해 적응력이 있습니다.

PHP를 사용하는 이유는 무엇입니까? 설명 된 장점과 혜택PHP를 사용하는 이유는 무엇입니까? 설명 된 장점과 혜택Apr 16, 2025 am 12:16 AM

PHP의 핵심 이점에는 학습 용이성, 강력한 웹 개발 지원, 풍부한 라이브러리 및 프레임 워크, 고성능 및 확장 성, 크로스 플랫폼 호환성 및 비용 효율성이 포함됩니다. 1) 배우고 사용하기 쉽고 초보자에게 적합합니다. 2) 웹 서버와 우수한 통합 및 여러 데이터베이스를 지원합니다. 3) Laravel과 같은 강력한 프레임 워크가 있습니다. 4) 최적화를 통해 고성능을 달성 할 수 있습니다. 5) 여러 운영 체제 지원; 6) 개발 비용을 줄이기위한 오픈 소스.

신화를 폭로 : PHP가 실제로 죽은 언어입니까?신화를 폭로 : PHP가 실제로 죽은 언어입니까?Apr 16, 2025 am 12:15 AM

PHP는 죽지 않았습니다. 1) PHP 커뮤니티는 성능 및 보안 문제를 적극적으로 해결하고 PHP7.x는 성능을 향상시킵니다. 2) PHP는 최신 웹 개발에 적합하며 대규모 웹 사이트에서 널리 사용됩니다. 3) PHP는 배우기 쉽고 서버가 잘 수행되지만 유형 시스템은 정적 언어만큼 엄격하지 않습니다. 4) PHP는 컨텐츠 관리 및 전자 상거래 분야에서 여전히 중요하며 생태계는 계속 발전하고 있습니다. 5) Opcache 및 APC를 통해 성능을 최적화하고 OOP 및 설계 패턴을 사용하여 코드 품질을 향상시킵니다.

PHP vs. Python 토론 : 어느 것이 더 낫습니까?PHP vs. Python 토론 : 어느 것이 더 낫습니까?Apr 16, 2025 am 12:03 AM

PHP와 Python에는 고유 한 장점과 단점이 있으며 선택은 프로젝트 요구 사항에 따라 다릅니다. 1) PHP는 웹 개발, 배우기 쉽고 풍부한 커뮤니티 리소스에 적합하지만 구문은 현대적이지 않으며 성능과 보안에주의를 기울여야합니다. 2) Python은 간결한 구문과 배우기 쉬운 데이터 과학 및 기계 학습에 적합하지만 실행 속도 및 메모리 관리에는 병목 현상이 있습니다.

PHP의 목적 : 동적 웹 사이트 구축PHP의 목적 : 동적 웹 사이트 구축Apr 15, 2025 am 12:18 AM

PHP는 동적 웹 사이트를 구축하는 데 사용되며 해당 핵심 기능에는 다음이 포함됩니다. 1. 데이터베이스와 연결하여 동적 컨텐츠를 생성하고 웹 페이지를 실시간으로 생성합니다. 2. 사용자 상호 작용 및 양식 제출을 처리하고 입력을 확인하고 작업에 응답합니다. 3. 개인화 된 경험을 제공하기 위해 세션 및 사용자 인증을 관리합니다. 4. 성능을 최적화하고 모범 사례를 따라 웹 사이트 효율성 및 보안을 개선하십시오.

PHP : 데이터베이스 및 서버 측 로직 처리PHP : 데이터베이스 및 서버 측 로직 처리Apr 15, 2025 am 12:15 AM

PHP는 MySQLI 및 PDO 확장 기능을 사용하여 데이터베이스 작업 및 서버 측 로직 프로세싱에서 상호 작용하고 세션 관리와 같은 기능을 통해 서버 측로 로직을 처리합니다. 1) MySQLI 또는 PDO를 사용하여 데이터베이스에 연결하고 SQL 쿼리를 실행하십시오. 2) 세션 관리 및 기타 기능을 통해 HTTP 요청 및 사용자 상태를 처리합니다. 3) 트랜잭션을 사용하여 데이터베이스 작업의 원자력을 보장하십시오. 4) SQL 주입 방지, 디버깅을 위해 예외 처리 및 폐쇄 연결을 사용하십시오. 5) 인덱싱 및 캐시를 통해 성능을 최적화하고, 읽을 수있는 코드를 작성하고, 오류 처리를 수행하십시오.

PHP에서 SQL 주입을 어떻게 방지합니까? (준비된 진술, pdo)PHP에서 SQL 주입을 어떻게 방지합니까? (준비된 진술, pdo)Apr 15, 2025 am 12:15 AM

PHP에서 전처리 문과 PDO를 사용하면 SQL 주입 공격을 효과적으로 방지 할 수 있습니다. 1) PDO를 사용하여 데이터베이스에 연결하고 오류 모드를 설정하십시오. 2) 준비 방법을 통해 전처리 명세서를 작성하고 자리 표시자를 사용하여 데이터를 전달하고 방법을 실행하십시오. 3) 쿼리 결과를 처리하고 코드의 보안 및 성능을 보장합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

VSCode Windows 64비트 다운로드

VSCode Windows 64비트 다운로드

Microsoft에서 출시한 강력한 무료 IDE 편집기

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.