PHP生成token防止表单重复提交2个例子

 更新时间:2016年11月25日 15:40  点击:1938
防止表单重复提交的解决方案非常的简单,我们下面两个例子都是生成一个随机的token验证用户是不是由我们站内提交并且进行重复验证即可实现了。

在网上搜索了一下有很多站长都这样说的

1、提交按钮置disabled

当用户提交后,立即把按钮置为不可用状态。这种用js来实现。
提交前代码如下:

 代码如下 复制代码

$("#submit").attr('disabled','true');
$("#submit").val("正在提交,请稍等");

执行后,把按钮置为原来状态
代码如下:

 代码如下 复制代码

$('#submit ').removeAttr('disabled');
$("#submit ").val("确定提交");

这样只是针对一些简单的前台提交了,如果我们自己做个表单站长提交给我们php逻辑层文件就过滤这那个js了。

过期时间法

用户提交按钮后生成一个token(每次业务提交token 为唯一值)存入session,并设置过期时间。当用户再此提交时,检测token是否一致且是否过期,若一致且没有过期,则认为提交了二次

例子

 代码如下 复制代码

<?php
/*
* PHP简单利用token防止表单重复提交
* 此处理方法纯粹是为了给初学者参考
*/
session_start();
function set_token() {
 $_SESSION['token'] = md5(microtime(true));
}

function valid_token() {
 $return = $_REQUEST['token'] === $_SESSION['token'] ? true : false;
 set_token();
 return $return;
}

//如果token为空则生成一个token
if(!isset($_SESSION['token']) || $_SESSION['token']=='') {
 set_token();
}

if(isset($_POST['test'])){
 if(!valid_token()){
  echo "token error";
 }else{
  echo '成功提交,Value:'.$_POST['test'];
 }
}
?>
<form method="post" action="">
 <input type="hidden" name="token" value="<?php echo $_SESSION['token']?>">
 <input type="text" name="test" value="Default">
 <input type="submit" value="提交" />
</form>

方法二

 代码如下 复制代码

<?php
//开启session
session_start();
//如果有提交标识
if(isset($_GET['action']) && $_GET['action'] === 'save'){

 //如果有session且跟传过来的值一样才算提交
 if(isset($_SESSION['__open_auth']) && isset($_POST['auth']) && $_SESSION['__open_auth'] == $_POST['auth']){
  print_r($_POST);
  $_SESSION['__open_auth'] = null;//清空
 } else {

  //走起
  header("location: post.php");
 }
 exit();
}

//授权
$auth = $_SESSION['__open_auth'] = time();

?>
<!doctype html>
<html>
<head>
 <meta charset="UTF-8">
 <title>post</title>
</head>
<body>
 <form action="post.php?action=save" method="post">
  <ul>
   <li>
    <input type="hidden" name="auth" value="<?php echo $auth;?>">
    <input type="text" name="userName">
   </li>
   <li>
    <input type="password" name="userpass">
   </li>
   <li>
    <input type="submit" value="走起">
   </li>
   <li>
    <?php echo time(); ?>
   </li>
  </ul>
 </form>
</body>
</html>

mysql php数据库重复记录防止

 代码如下 复制代码

<?php
$link=mysql_connect(‘localhost’,’root’,’1234’); //得到MySQL数据库连接
$username=$_GET["name"]; //得到从客户端表单传过来的数据
$q="select * from usertable where user_name='$username'";
mysql_query("SET NAMES gb2312"); //避免出现中文乱码
$rs = mysql_query($q, $link); //查询数据库
$num_rows = mysql_num_rows($rs); //得到查询结果的总行数
if($num_rows==0)
// 烈火? liehuo.net 欢迎复制,拒绝恶意采集 liehuo.net
{
$exec="insert into student (user_name) values ($username)";
mysql_query("SET NAMES gb2312");
mysql_query($exec, $link); //若没有此用户则将数据插入到数据库(注册用户)
echo "用户注册成功!";
}
else
{
echo "该用户名已存在,请重新选择用户名!";
}
?>

session过期法有非常重要的一点是一个session设置与提交成功与不成功时的一个session验证了,这个有点像登录一样的如果登录成功了我们要清除session这个原理也差不多。

下面有两种方法实现用户登录了,一个是无数据库直接登录功能,一个是有数据库查询判断登录,后者是我们最常用的管理权限与后台登录功能,希望对各位有帮助哦。

用户登录系统(没数据库)

关键的代码:
在loginUI.php中主要是:
——————————————————————————–

 代码如下 复制代码
<?php
if(error!=null){
$error=$_GET['error'];
echo $error;
echo “登陆失败,请检查您的用户名(yugaga)和密码(123456)”;
}
?>

————————————————————————————
就是在登录失败之后显示一些提示信息
在loginCheck.php中
————————————————————————————–

 代码如下 复制代码
<?php
$username=$_POST['username'];
$password=$_POST['password'];
if($username==”yugaga”&&$password==”123456″){
$host  = $_SERVER['HTTP_HOST'];
$uri   = rtrim(dirname($_SERVER['PHP_SELF']), ‘/’);
$extra = ‘welcome.php?user=’.$username;
header(“Location: http://$host$uri/$extra“);
}else {
$host  = $_SERVER['HTTP_HOST'];
$uri   = rtrim(dirname($_SERVER['PHP_SELF']), ‘/’);
$extra = ‘loginUI.php?error=failer’;
header(“Location: http://$host$uri/$extra“);
}
?>

———————————————————————————————————-
主要是对提交的信息进行验证,这里面用到了正则匹配,和全局变量
在welcome.php中,主要输出信息
———————————————————————————————————-

 代码如下 复制代码
<?php
$username=$_GET['user'];
echo “欢迎”.$username.”的登陆”;
?>

用户登录系统(有数据库)

我们试着去连接数据库。主要是增添加了两个文件,一个SqlHepler.php,用来获得数据库的连接,一个userService.php文件,用来处理和用户相关的操作,比如用户登录的验证,在本次中,我们只是添加了一个函数checkUserLogin($username,$password),根据用户名和密码判断用户是不是登录成功!~

html 代码

 代码如下 复制代码

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <title>简单的登陆演示 </title>
 </head>

 <body>
 <center>
  <form action="loginCheck.php" method="post">
   用户账号:<input type="text" name="username" size="20"/><br/>
   用户秘密:<input type="password" name="password" size="20"/><br/>
   <input type="submit" value="提交"/>
  </form>
  <?php
 $error=$_GET['error'];
 if($error=='failer'){
  echo "登陆失败,请检查您的用户名(yugaga)和密码(123456)";
 }
?>
  </center>

 </body>
</html>


主要代码:
——————————————————————————————————-
<?php
include_once ‘SqlHelper.php’;
function checkUserLogin($username,$password){
$res=mysql_query(“select *from users where username=’”.$username.”‘”);
if(($listuser=mysql_fetch_array($res))!=null){
if($listuser[2]==$password){
return true;
}
}else {
return false;
}
}
?>
————————————————————————————————————-
SqlHelper的代码:
————————————————————————————————————
<?php
$server=”localhost”;
$user=”root”;
$pass=””;
$con=mysql_connect($server,$user,$pass);
mysql_select_db(“login”,$con);
?>
————————————————
登录成功之后代码

<?php
 $username=$_GET['user'];
 echo "欢迎".$username."的登陆";
?>

取所有内容中图片的地址我们必须使用正则表达式来匹配了,如果不使用它来匹配我们是无法获取到或才能获取到也是非常的麻烦了,下面我们一起来看看我整理了几段匹配图片地址程序代码吧。

图片网址规范的html代码无非就是

《img title="??" src="/wp-admin/%E5%9B%A73" alt="??" title="??" width="5" height="6" /》

??和??是非必需的,若要通过XHTML认证??、??、??必不可少,??是核心内容,当然就不能少了。

就正则谈正则的话,我写出的最短匹配是

(?<=img.+?src=").*?(?=")

不过,这条在php里不行,会出现:

Warning: preg_match_all() [function.preg-match-all]: Compilation failed: lookbehind assertion is not fixed length at offset *** in ***

纠结了很久,都不行,原因何在呢?试了很多次,终于发现问题在(?<=img.+?src=")这个零宽断言里,在php中,零宽断言里不支持类似“*”、“+”这些无限次的东西,于是报错了,把“.+?”改为定长就好。不过,要“img”和“src=”之间定长基本上是不可能的。通常,图片地址的img和src只会相隔一个很简单的空格,但不排除某些情况在src之前,img后有alt、titlte等东西。

所以

(?<=img.src=").*?(?=")

(?<=img\ssrc=").*?(?=")

可能可以,但不保证100%没问题。

你也许会问,单纯

(?<=src=").*?(?=")

不行吗?通常情况,可以,但,搜索过页面的盆友应该知道,除了图片地址用src开头以外,javascript地址也用src开头!而且,太多神通广大的不可预知因素隐含其中,于是这个貌似很简短完美的写法就行不通了。

你又或许会问,聪明简短的不行,我把图片的后缀列出来,总该可以了吧,如

(?<=src=").*?\.(jpg|jpeg|gif|png|bmp|JPG|JPEG|GIF|PNG|BMP)

的确,这个写法实在是很老实,不过,你见过没有后缀的图片?wwe.com 有很多这种例子呢

段一,匹配地址方法

内容:

 代码如下 复制代码

<a href="/item/2864756" target="_blank"><img src="/pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg" height="268" width="200px"/></a>
<a href="/item/2864756" target="_blank"><img src="/pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg" height="268" width="200px"/></a>
<a href="/item/2864756" target="_blank"><img src="/pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg" height="268" width="200px"/></a>

PHP代码:

$p = "/src=\"([^\"]+)/isu";
//$p = "/<[^>]+>/isu";
//$p = "/<a[^>]+>/isu";
preg_match_all($p, $html, $m);
var_dump($m);

结果:

Array
(
    [0] => Array
        (
            [0] => src="/pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg
            [1] => src="/pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg
            [2] => src="/pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg
          
 
    [1] => Array
        (
            [0] => /pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg
            [1] => /pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg
            [2] => /pic/r/e6/14/28b4766b65373ae6a3b3faccc81f_400_536.jpg
          
        )
 
)

段二,

 代码如下 复制代码

newstext=preg_replace(preg_replace('/(<img[^>]+src\s*=\s*”?([^>"\s]+)”?[^>]*>)/im', ‘<a href=”$2″>$1</a>', $newstext);

1.preg_replace和str_replace的区别:

str_replace只是纯字符替换,而preg_replace才是正则替换

2.$0,$1,$2等的说明:

$0指的是被整个模式所匹配的文本;

$1指的是首个 ( ) 引用的串;

$2指的是第二个()引用的串; 以此类推。

网页返回状态代码很多站长会去查自己网站状态码是不是200或错误页面是不是404代码了,那么我们使用最多的查看方法就是使用站长工具或ff浏览器来查,但有很多朋友不知道可以自己写一个查看状态代码的功能哦。

方法一,使用 fsockopen

严重鄙视curl_getinfo!

 代码如下 复制代码

function get_http_code($url="localhost", $port=80, $fsock_timeout=10){
    set_time_limit(0);
    ignore_user_abort(true);
 
    // 记录开始时间
    list($usec, $sec) = explode(" ", microtime(true));
    $timer['start'] = (float)$usec + (float)$sec;
 
    // 校验URL
    if(!preg_match("/^https?:\/\//i", $url)){
        $url = "http://".$url;
    }
    // 支持HTTPS
    if(preg_match("/^https:\/\//i", $url)){
        $port = 443;
    }
 
    // 解析URL
    $urlinfo = parse_url($url);
    if(empty($urlinfo['path'])){
        $urlinfo['path'] = '/';
    }
    $host = $urlinfo['host'];
    $uri = $urlinfo['path'] . (empty($urlinfo['query'])?'':$urlinfo['query']);
 
    // 通过fsock打开连接
    if(!$fp = fsockopen($host, $port, $errno, $error, $fsock_timeout)){
        list($usec, $sec) = explode(" ", microtime(true));
        $timer['end'] = (float)$usec + (float)$sec;
        $usetime = (float)$timer['end'] - (float)$timer['start'];
 
        return array('code'=>-1, 'usetime'=>$usetime);
    }
 
    // 提交请求
    $status = socket_get_status($fp);
    $out = "GET {$uri} HTTP/1.1\r\n";
    $out .= "Host: {$host}\r\n";
    $out .= "Connection: Close\r\n\r\n";
    $write = fwrite($fp, $out);
    if(!$write){
        list($usec, $sec) = explode(" ", microtime(true));
        $timer['end'] = (float)$usec + (float)$sec;
        $usetime = (float)$timer['end'] - (float)$timer['start'];
 
        return array('code'=>-2, 'usetime'=>$usetime);
    }
 
    $ret = fgets($fp, 1024);
    preg_match("/http\/\d\.\d\s(\d+)/i", $ret, $m);
    $code = $m[1];
    fclose($fp);
 
    list($usec, $sec) = explode(" ", microtime(true));
    $timer['end'] = (float)$usec + (float)$sec;
    $usetime = (float)$timer['end'] - (float)$timer['start'];
 
    return array('code'=>$code, 'usetime'=>$usetime);
}

file_get_contents 是 fsockopen 功能的简单打包,效率稍低些,但是抓取成功率很高,所以在 snoopy 出问题的时候我一般那他来。5.0.0 添加了对 context 的支持,有了context,他也可以发送 header 信息,自定义用户 agent, referer, cookies 都不在话下。5.1.0 添加了 offset 和 maxlen 参数,可以只读文件的一部分内容。

方法二,使用snoopy.class.php

Snoopy是一个php类,用来模拟浏览器的功能,可以获取网页内容,发送表单。

 代码如下 复制代码

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.spiegel.de/');
curl_setopt($ch, CURLOPT_RANGE, '0-500');
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
/**
*But as noted before if the server doesn't honor this header but sends the whole file curl will download all of it. E.g. http://www.111cn.net ignores the header. But you can (in addition) set a write function callback and abort the request when more data is received, e.g.
* php 5.3+ only
* use function writefn($ch, $chunk) { ... } for earlier versions
*/
$writefn = function($ch, $chunk) {
  static $data='';
  static $limit = 500; // 500 bytes, it's only a test
  $len = strlen($data) + strlen($chunk);
  if ($len >= $limit ) {
    $data .= substr($chunk, 0, $limit-strlen($data));
    echo strlen($data) , ' ', $data;
    return -1;
  }
  $data .= $chunk;
  return strlen($chunk);
};
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.111cn.net/');
curl_setopt($ch, CURLOPT_RANGE, '0-500');
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $writefn);
$result = curl_exec($ch);
curl_close($ch);

一些常见的状态码为:

200 - 服务器成功返回网页
404 - 请求的网页不存在
503 - 服务器超时
301 - 页面重定向

为了更好的控制php程序同时操作的一些问题我整理了一个进程锁的类我们可以利用这个进程锁实现程序的控制

程序代码如下

 代码如下 复制代码

<?php
//+----------------------------------------------
//|    Usage:
//+----------------------------------------------
//|    public function _initialize(){
//|        import('@.Util.PHPLock');
//|
//|        if(PHPLock::islocked()){
//|            echo "[+] Status: Locked\n";
//|            echo "[+] Exit\n";
//|            exit();
//|        }else{
//|            echo "[+] Status: Unlocked\n";
//|            echo "[-] Locking Now\n";
//|            PHPLock::lock();
//|        }
//|    }
//|
//|    function __destruct(){
//|        if(true === PHPLock::unlock()){
//|            echo "[+] Unlock Success\n";
//|        }
//|    }
//+----------------------------------------------
class PHPLock
{
    const PHPLOCK_TIMEOUT = 1200;
    static private $pid = null;
   
    static public function lock(){
        $key = self::__getKey();
        self::$pid = time();
        F($key, self::$pid);
        return true;
    }
   
    static public function unlock(){
        $key = self::__getKey();
        if(self::$pid){
            F($key, null);
            return true;
        }
        return;
    }
   
    static public function islocked(){
        $key = self::__getKey();
        $time = F($key);

        if(!$time){
            return false;
        }elseif(time() - $time >= self::getTimeout()){
            self::unlock();
            return false;
        }else{
            return true;
        }
    }
   
    static public function getTimeout(){
        $key = str_replace(self::__getKey(), '_Lock', '_TIMEOUT');
        $expire = C($key) ? C($key) : self::PHPLOCK_TIMEOUT;
        return $expire;
    }
   
    static private function __getKey(){
        return (defined('GROUP_NAME') ? GROUP_NAME.'_' : '') . MODULE_NAME . '_' . ACTION_NAME . '_Lock';
    }
}
?>

[!--infotagslink--]

相关文章

  • JS中artdialog弹出框控件之提交表单思路详解

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口。本文给大家介绍JS中artdialog弹出框控件之提交表单思路详解,对本文感兴趣的朋友一起学习吧...2016-04-19
  • php二维码生成

    本文介绍两种使用 php 生成二维码的方法。 (1)利用google生成二维码的开放接口,代码如下: /** * google api 二维码生成【QRcode可以存储最多4296个字母数字类型的任意文本,具体可以查看二维码数据格式】 * @param strin...2015-10-21
  • Java生成随机姓名、性别和年龄的实现示例

    这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
  • C#生成随机数功能示例

    这篇文章主要介绍了C#生成随机数功能,涉及C#数学运算与字符串操作相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • jQuery为动态生成的select元素添加事件的方法

    下面小编就为大家带来一篇jQuery为动态生成的select元素添加事件的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-09-01
  • php生成唯一数字id的方法汇总

    关于生成唯一数字ID的问题,是不是需要使用rand生成一个随机数,然后去数据库查询是否有这个数呢?感觉这样的话有点费时间,有没有其他方法呢?当然不是,其实有两种方法可以解决。 1. 如果你只用php而不用数据库的话,那时间戳+随...2015-11-24
  • PHP自动生成后台导航网址的最佳方法

    经常制作开发不同的网站的后台,写过很多种不同的后台导航写法。 最终积累了这种最写法,算是最好的吧...2013-09-29
  • sqlserver删除重复记录并且要保留一条记录

    删除重复数据,只保留一条用SQL语句,删除掉重复项只保留一条在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢...2018-09-10
  • angularjs $http实现form表单提交示例

    这篇文章主要介绍了angularjs $http实现form表单提交示例,非常具有实用价值,需要的朋友可以参考下 ...2017-06-15
  • vue项目,代码提交至码云,iconfont的用法说明

    这篇文章主要介绍了vue项目,代码提交至码云,iconfont的用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-30
  • js生成随机数的方法实例

    js生成随机数主要用到了内置的Math对象的random()方法。用法如:Math.random()。它返回的是一个 0 ~ 1 之间的随机数。有了这么一个方法,那生成任意随机数就好理解了。比如实际中我们可能会有如下的需要: (1)生成一个 0 - 1...2015-10-21
  • html表单提交中method请求Get和Post区别详解

    在html表单提交中method请求Get和Post区别其实很显示的,get提交会是url形式的并且数据量不能太多,而post数据是在浏览器url看不到的并且可以是大数据量而且get安全性非...2016-09-20
  • C#删除字符串中重复字符的方法

    这篇文章主要介绍了C#删除字符串中重复字符的方法,涉及C#针对字符串的遍历及移除等操作的技巧,非常具有实用价值,需要的朋友可以参考下...2020-06-25
  • PHP验证码生成与验证例子

    验证码是一个现在WEB2.0中常见的一个功能了,像注册、登录又或者是留言页面,都需要注册码来验证当前操作者的合法性,我们会看到有些网站没有验证码,但那是更高级的验证了,...2016-11-25
  • PHP生成不同颜色、不同大小的tag标签函数

    复制代码 代码如下:function getTagStyle(){ $minFontSize=8; //最小字体大小,可根据需要自行更改 $maxFontSize=18; //最大字体大小,可根据需要自行更改 return 'font-size:'.($minFontSize+lcg_value()*(abs($maxFo...2013-10-04
  • postgresql 删除重复数据的几种方法小结

    这篇文章主要介绍了postgresql 删除重复数据的几种方法小结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • php中利用str_pad函数生成数字递增形式的产品编号

    解决办法:$str=”QB”.str_pad(($maxid[0]["max(id)"]+1),5,”0″,STR_PAD_LEFT ); 其中$maxid[0]["max(id)"]+1) 是利用max函数从数据库中找也ID最大的一个值, ID为主键,不会重复。 str_pad() 函数把字符串填充为指...2013-10-04
  • JS生成某个范围的随机数【四种情况详解】

    下面小编就为大家带来一篇JS生成某个范围的随机数【四种情况详解】。小编觉得挺不错的,现在分享给大家,也给大家做个参考,一起跟随小编过来看看吧...2016-04-22
  • C#生成Word文档代码示例

    这篇文章主要介绍了C#生成Word文档代码示例,本文直接给出代码实例,需要的朋友可以参考下...2020-06-25
  • 基于Postgresql 事务的提交与回滚解析

    这篇文章主要介绍了基于Postgresql 事务的提交与回滚解析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-18