php分步骤表单试水

这几天马上要出国,于是乎需要收集所有同学国内行程情况的我本着 在空调房里不愿意出去让同学填纸质表 为人民服务的态度,花了一个多小时写了一个php表单 ,这下大家都不用出空调房了

表单本身很简单,由于需要快速上线采用单index.php页面,源码如下:

<?php
class db {
	public $host='';
	public $username='';
	public $password='';
	public $dbname='';
}
//连接数据库,由于隐私原因db内字段省略
$db=new db();
$dsn = "mysql:host=".$db->host.";dbname=".$db->dbname.";charset=utf8";
$db = new PDO($dsn, $db->username, $db->password);
date_default_timezone_set('Asia/Shanghai');

$step=1;
if(isset($_POST["phone"])){
    $step=2;
    $rs=$db->query("select * from stanford where phone=".addslashes($_POST["phone"]).";");
    if($row=$rs->fetch()) {
        $name=$row['name'];
        $phone=$row['phone'];
        $uid=$row['uid'];
    } else {
        $step=3;
        $msg="未找到该电话号码!";
    }
}
if(isset($_POST["departure"])){
    $step=3;
    if($_POST["departure"]==1){
        $departure="学校";
    } else {
        if($_POST["departure"]==2){
            $departure="家长送机(";
        }else{
            $departure="家(";
        }
        $departure=$departure.$_POST["city_departure"].")";
    }
    if($_POST["arrival"]==1){
        $arrival="学校";
    } else {
        if($_POST["arrival"]==2){
            $arrival="家长接机(";
        }else{
            $arrival="家(";
        }
        $arrival=$arrival.$_POST["city_arrival"].")";
    }
    $uid=$_POST["uid"];
    $pre="update stanford set `departure` =  '".$departure."' , `arrival` =  '".$arrival."' where uid=".$uid;
    //echo $pre;
    $rs=$db->query($pre);
    if($rs) {
        $msg="提交完成!";
    } else {
        $msg="未知错误!";
    }
}
function getIP() { 
	if (@$_SERVER["HTTP_X_FORWARDED_FOR"]) 
		$ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; 
	else if (@$_SERVER["HTTP_CLIENT_IP"]) 
		$ip = $_SERVER["HTTP_CLIENT_IP"]; 
	else if (@$_SERVER["REMOTE_ADDR"]) 
		$ip = $_SERVER["REMOTE_ADDR"]; 
	else if (@getenv("HTTP_X_FORWARDED_FOR"))
		$ip = getenv("HTTP_X_FORWARDED_FOR"); 
	else if (@getenv("HTTP_CLIENT_IP")) 
		$ip = getenv("HTTP_CLIENT_IP"); 
	else if (@getenv("REMOTE_ADDR")) 
		$ip = getenv("REMOTE_ADDR"); 
	else 
		$ip = "Unknown"; 
	return $ip; 
}
?>

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Stanford</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="format-detection" content="telephone=no">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <link rel="alternate icon" type="image/png" href="https://static.1cf.co/favicon.png">
    <link href="https://fonts.geekzu.org/css?family=Roboto:300,300i,400,400i,500,500i,700,700i" rel="stylesheet">
    <link href="https://fonts.geekzu.org/icon?family=Material+Icons" rel="stylesheet">
    <link href="https://static.1cf.co/css/material.min.css" rel="stylesheet">
    <style>
        body{
            background: url(https://static.1cf.co/img/stanford/wooden3.jpg) 0 / contain fixed;
        }
        .col-sm-2 {
            -webkit-box-flex: 0;
            -webkit-flex: 0 0 16.666667%;
            -ms-flex: 0 0 16.666667%;
            flex: 0 0 16.666667%;
            max-width: 16.666667%;
        }
        .col-sm-10 {
            -webkit-box-flex: 0;
            -webkit-flex: 0 0 83.333333%;
            -ms-flex: 0 0 83.333333%;
            flex: 0 0 83.333333%;
            max-width: 83.333333%;
        }
    </style>
  </head>
<body>
<div class="container">
<div class="row justify-content-sm-center">
  <div class="col-sm-6">
<div class="card text-center" style="margin-top:20vh;margin-bottom:20vh;">
  <div class="card-header">
    当前IP:<?php echo getIP();?>
  </div>
  <div class="card-body">
    <form action="" method="post">
    <h4 class="card-title">斯坦福访学国内行程登记表</h4>
    <?php if($step==1){ ?>
    <div class="form-group">
        <label for="phone">请先填写登记的手机号</label>
        <div class="form-group row">
            <label class="col-sm-2 col-form-label">手机</label>
            <div class="col-sm-10">
                <input type="tel" class="form-control" name="phone" placeholder="输入手机号……" required>
            </div>
        </div>
    </div>
    <button type="submit" class="btn btn-primary">下一步</button>
    <?php } else if($step==2) { ?>
    <div class="form-group">
        <hr>
        <div class="form-group my-3">
            <h5 for="basic">基本信息(请核对)</h5>
            <input type="hidden" name="uid" value="<?php echo $uid; ?>">
            <div class="form-group row">
                <label class="col-sm-2 col-form-label">姓名</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" placeholder="<?php echo $name; ?>" disabled>
                </div>
            </div>
            <div class="form-group row">
                <label class="col-sm-2 col-form-label">电话</label>
                <div class="col-sm-10">
                    <input type="tel" class="form-control" placeholder="<?php echo $phone; ?>" disabled>
                </div>
            </div>
        </div>
        <hr>
        <div class="form-group my-3">
            <h5 for="departure">出发(1月21日)</h5>
            <div class="custom-controls-stacked d-block my-3">
                <label class="custom-control custom-radio">
                  <input id="radioStacked1" name="departure" value="1" type="radio" class="custom-control-input departure" required>
                  <span class="custom-control-indicator"></span>
                  <span class="custom-control-description">学校</span>
                </label>
                <label class="custom-control custom-radio">
                  <input id="radioStacked2" name="departure" value="2" type="radio" class="custom-control-input departure" required>
                  <span class="custom-control-indicator"></span>
                  <span class="custom-control-description">家长送机</span>
                </label>
                <label class="custom-control custom-radio">
                  <input id="radioStacked2" name="departure" value="3" type="radio" class="custom-control-input departure" required>
                  <span class="custom-control-indicator"></span>
                  <span class="custom-control-description">家</span>
                </label>
                <div class="form-group row" id="city_departure_row" style="display:none;">
                    <label class="col-sm-2 col-form-label">城市</label>
                    <div class="col-sm-10">
                        <input type="text" class="form-control" name="city_departure"  placeholder="具体城市">
                    </div>
                </div>
            </div>
            <small class="form-text text-muted">从何处出发前往浦东机场(如非从学校出发,请填写家所在具体城市)。</small>
        </div>
        <hr>
        <div class="form-group my-3">
            <h5 for="arrival">回国(2月3日)</h5>
            <div class="custom-controls-stacked d-block my-3">
                <label class="custom-control custom-radio">
                  <input id="radioStacked4" name="arrival" value="1" type="radio" class="custom-control-input arrival" required>
                  <span class="custom-control-indicator"></span>
                  <span class="custom-control-description">学校</span>
                </label>
                <label class="custom-control custom-radio">
                  <input id="radioStacked5" name="arrival" value="2" type="radio" class="custom-control-input arrival" required>
                  <span class="custom-control-indicator"></span>
                  <span class="custom-control-description">家长接机</span>
                </label>
                <label class="custom-control custom-radio">
                  <input id="radioStacked6" name="arrival" value="3" type="radio" class="custom-control-input arrival" required>
                  <span class="custom-control-indicator"></span>
                  <span class="custom-control-description">家</span>
                </label>
                <div class="form-group row"  id="city_arrival_row" style="display:none;">
                    <label class="col-sm-2 col-form-label">城市</label>
                    <div class="col-sm-10">
                        <input type="text" class="form-control" name="city_arrival"  placeholder="具体城市">
                    </div>
                </div>
            </div>
            <small class="form-text text-muted">如回家,请填写具体城市。</small>
        </div> 
        <hr>
        <label class="custom-control custom-checkbox mb-2 mr-sm-2 mb-sm-0">
            <input type="checkbox" name="verify" class="custom-control-input" required>
            <span class="custom-control-indicator"></span>
            <span class="custom-control-description">上述信息无误</span>
        </label>
    </div>
    <button type="submit" class="btn btn-primary">下一步</button>
    <? } else { ?>
        <p class="card-text" for="tips"><?php echo $msg; ?></p>
        <a href="./" class="btn btn-primary">确定</a>
    <? } ?>
    </form>
  </div>
  <div class="card-footer text-muted">
    <a href="https://www.johnzhang.xyz" target="_blank">&copy;  John Zhang</a> 
  </div>
</div>
  </div>
</div>
</div>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://static.1cf.co/js/jquery-3.2.1.slim.min.js"></script>
    <script src="https://static.1cf.co/mirror/cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
    <script src="https://static.1cf.co/js/bootstrap.min.js"></script>
    <!-- Then Material JavaScript on top of Bootstrap JavaScript -->
    <script src="https://static.1cf.co/js/material.min.js"></script>
    <script>
    $(".departure").change(  
        function() {  
        var id = $("input[name='departure']:checked").val();  
        if(id!=1) $("#city_departure_row").css("display","flex");
        else $("#city_departure_row").css("display","none");
    }); 
    $(".arrival").change(  
        function() {  
        var id = $("input[name='arrival']:checked").val();  
        if(id!=1) $("#city_arrival_row").css("display","flex");
        else $("#city_arrival_row").css("display","none");
    }); 
    </script>
  </body>
</html>

最上端是后端处理内容,后面则是html内容。
几个注意点:

  1. 在后端,首先需要判断到了哪一步,这里,表单分三步走,第一步输入手机号验证身份,第二返回用户姓名给用户核对并要求填写出国时和回国时的情况,第三步返回成功/失败信息。
  2. 由于第三步充当返回信息的职责,因此在编写过程中,如果出现错误我将直接跳转step到3并且附上msg。正文部分,通过step变量的值判断显示哪一部分。
  3. 判断第几步时的思路时判断有没有当前步才会被接收的POST参数,这里使用了isset();。
  4. 由于内部页面,并没有太多关注XSS防护,在第二步所使用addslashes()可以被copy到第三步,用法同,另外$db->query直接拼接字符串的方法也有安全隐患,建议$db->prepare然后传递参数。唉,一个字,懒。
  5. 第三步判断时使用了uid,这里存在安全隐患,用户有可能会去魔改uid或者直接构造post,合理的方法是session存储uid,然后对于session有uid的用户跳过第一步直接上第二步,直到用户点击上一步(清除session),不过这样就要增加一个按钮和很多代码。唉,一个字,懒。
  6. CSS使用纹理拼接时使用了contain,这在会导致图片在某些手机浏览器被扭曲。
  7. CSS中重定义了col-sm-10与col-sm-2,这是因为我所使用的material框架在小于600px(@media (min-width: 600px))的时候会放弃12等分layout布局,任何col的width都会变成100%。
  8. HTML中使用了php判断显示,这种做法其实是不被推荐的,但是……懒。
  9. 第二步选择时需要在选项不是学校时显示一个输入框,这有点类似radio里面的其它选项,这里JS采用监视统一class,判断radiobox值并通过jQuery修改css的display属性的方式。

留下你的评论呗...

电子邮件地址不会被公开。 必填项已用*标注