專題製作一-上課補充教材


會員的註冊系統
  1. 會員的註冊需要注意的項目:為了擔心被攻擊,你的註冊一定需要考慮到帳號的英數限制
    1. 因為常有 SQL injection 的攻擊,因此建議,你的『帳號』應該要加入不少的限制比較妥當! 舉例來說,例如只能是英文與數字,最多還有底線或減號以及小數點,其他的就予以限制這樣比較妥當。
    2. 密碼欄位當然一定要編碼加密,我們在本案例中,選擇使用簡單的 sha256 (hash('sha256',$pw)) 來處理密碼欄位! 越嚴格的密碼所佔的表單欄位寬度要更長!
    3. 最好有防呆的機制,例如不能有相同的帳號名稱、不能不輸入密碼、限制密碼最小長度等等,都是一些基本的限制與考量。
    4. 最好能夠讓管理員來放行使用者的註冊!不要一經註冊就能使用 (當然,也可以加上許多的註冊機器人防治手法!)
  2. 開始建立註冊的基本頁面 (註冊所需要的資料通通列在上面喔!)
    $ vim register.php
    
    <?php
            include ('include/config.php');
    ?>
    <!doctype html>
    <html>
    <head>
            <meta charset='utf-8' />
    </head>
    <body>
    
    <form>
    <table>
            <tr>
                    <td>登入帳號:</td>
                    <td><input type="text" name="login_name" required="required" /></td>
                    <td>帳號只能是英文、數字、底線、減號與小數點,其餘字元均不接受</td>
            </tr>
            <tr>
                    <td>登入密碼:</td>
                    <td><input type="password" name="login_pass11" required="required" /></td>
                    <td>至少 5 個位數以上的密碼長度</td>
            </tr>
            <tr>
                    <td>確認密碼:</td>
                    <td><input type="password" name="login_pass12" required="required" /></td>
                    <td>再輸入一次密碼,確認沒有打錯字</td>
            </tr>
            <tr>
                    <td>真實姓名:</td>
                    <td><input type="text" name="realname" required="required" /></td>
                    <td>填寫註冊者的姓名</td>
            </tr>
            <tr>
                    <td>電子郵件:</td>
                    <td><input type="email" name="u_email" /></td>
                    <td>請填慣用的電子郵件</td>
            </tr>
            <tr>
                    <td>生日:</td>
                    <td><input type="date" name="u_bday" required="required" /></td>
                    <td>請務必使用 YYYY-MM-DD 的格式,如 1990-01-20</td>
            </tr>
            <tr>
                    <td>性別:</td>
                    <td><select name="u_sex">
                            <option value="0">女性</option>
                            <option value="1">男性</option>
                    </select></td>
                    <td>選擇性別</td>
            </tr>
            <tr>
                    <td colspan="3" style="text-align:center; ">
                            <input type="hidden" name="action" value="reg" />
                            <input type="submit" value="送出註冊" />
                    </td>
            </tr>
    
    </table>
    </form>
    
    </body>
    </html>
    
  3. 開始設計防呆的樣式!注意到許多 javascript 的應用喔!尤其是正規表示法的部份:
    $ vim register.php
    
    <?php
            include ('include/config.php');
    ?>
    <!doctype html>
    <html>
    <head>
            <meta charset='utf-8' />
    </head>
    <body>
    
    <form id="regform" onsubmit="return checkinput()" >
    <table>
            <tr>
                    <td>登入帳號:</td>
                    <td><input type="text" name="login_name" required="required" id='login_name' /></td>
                    <td>帳號只能是英文、數字、底線、減號與小數點,其餘字元均不接受</td>
            </tr>
            <tr>
                    <td>登入密碼:</td>
                    <td><input type="password" name="login_pass1" required="required" id='login_pass1' /></td>
                    <td>至少 5 個位數以上的密碼長度</td>
            </tr>
            <tr>
                    <td>確認密碼:</td>
                    <td><input type="password" name="login_pass2" required="required" id='login_pass2' /></td>
                    <td>再輸入一次密碼,確認沒有打錯字</td>
            </tr>
            <tr>
                    <td>真實姓名:</td>
                    <td><input type="text" name="realname" required="required" /></td>
                    <td>填寫註冊者的姓名</td>
            </tr>
            <tr>
                    <td>電子郵件:</td>
                    <td><input type="email" name="u_email" /></td>
                    <td>請填慣用的電子郵件</td>
            </tr>
            <tr>
                    <td>生日:</td>
                    <td><input type="date" name="u_bday" required="required" id='bday' /></td>
                    <td>請務必使用 YYYY-MM-DD 的格式,如 1990-01-20</td>
            </tr>
            <tr>
                    <td>性別:</td>
                    <td><select name="u_sex">
                            <option value="0">女性</option>
                            <option value="1">男性</option>
                    </select></td>
                    <td>選擇性別</td>
            </tr>
            <tr>
                    <td colspan="3" style="text-align:center; ">
                            <input type="hidden" name="action" value="reg" />
                            <input type="submit" value="送出註冊" />
                    </td>
            </tr>
    
    </table>
    </form>
    <script>
            function checkinput() {
                    // 檢查登入帳號是否有特殊字元
                    var re = /[^a-zA-Z0-9.-_]/;
                    var okname = re.exec ( document.getElementById("login_name").value);
                    if ( okname ) {
                            window.alert ( "指允許英文、數字、底線、小數點與減號" );
                            document.getElementById("login_name").focus();
                            return false;
                    }
    
                    // 開始檢查密碼長度是否正確?
                    var pw1 = document.getElementById("login_pass1");
                    if ( pw1.value.length < 5 ) {
                            window.alert ( "密碼長度必須要大於 5 個字元以上" );
                            document.getElementById("login_pass1").focus();
                            return false;
                    }
    
                    // 看看兩次密碼是否相同?
                    var pw2 = document.getElementById("login_pass2");
                    if ( pw1.value != pw2.value ) {
                            window.alert ( "兩次密碼並不相同!" );
                            document.getElementById("login_pass1").focus();
                            return false;
                    }
    
                    // 檢查生日的格式正確與否
                    re = /^[0-9]{4}[./-][0-9]{2}[./-][0-9]{2}$/;
                    var okday = re.exec ( document.getElementById("bday").value);
                    if ( ! okday ) {
                            window.alert ( "日期格式為 2011-11-11" );
                            document.getElementById("bday").focus();
                            return false;
                    }
            }
    
    </script>
    
    </body>
    </html>
    
  4. 若一切檢查都正確,當然就是要開始上傳了。上傳時,請注意到資料還是得要加入 SQL 語法的檢驗喔!
    $ vim register.php
    
    <?php
            include ('include/config.php');
    
            if ( isset ( $_REQUEST['action'] ) ) {
                    if ( $_REQUEST['action'] == 'reg' ) {
                            // 先取得所需要的變數資料
                            $login_name  = $_REQUEST['login_name'];
                            $login_pass1 = $_REQUEST['login_pass1'];
                            $login_pass2 = $_REQUEST['login_pass2'];
                            $realname    = $_REQUEST['realname'];
                            $u_email     = $_REQUEST['u_email'];
                            $u_bday      = $_REQUEST['u_bday'];
                            $u_sex       = $_REQUEST['u_sex'];
    
                            // 檢查登入者的帳號長度
                            if ( strlen($login_name) < 5 ) {
                                    echo"<script>alert('登入帳號字元不足 5 個字元');history.go(-1);</script>";
    				die;
                            }
                            if ( $login_pass1 != $login_pass2 ) {
                                    echo"<script>alert('兩次密碼輸入不相同');history.go(-1);</script>";
    				die;
                            }
                            $login_pass = hash ('sha256', $login_pass1);
                            $sql = "insert into userinfo (login_name,login_pass,realname,u_email, u_bday,u_sex) values (" .
                                    "'$login_name', "   .
                                    "'$login_pass', "  .
                                    "'$realname', "  .
                                    "'$u_email', "  .
                                    "'$u_bday', "  .
                                    "'$u_sex' ) " ;
                            $result = mysql_query ($sql, $db_link );
                            if ( $result ) {
                                    header("Location: listuser.php");
                            } else {
                                    echo"<script>alert('無法註冊!');history.go(-1);</script>";
    				die;
                            }
    
                    }
            }
    ?>
    <!doctype html>
    後續的資料不變
    
  5. 雖然寫入了資料庫,但是並沒有防呆!所以,這時開始來防呆一下!
    $ vim register.php
    
    //只要新增這一塊,請放在『 $login_pass = hash ('sha256', $login_pass1); 』這一行的前面就可以了!
                            // 先查一下有沒有這個帳號存在了?
                            $sql = "select * from userinfo where login_name = '$login_name'";
                            $result = mysql_query ($sql, $db_link );
                            $db_line = mysql_num_rows($result);
                            if ( $db_line >= 1 ) {
                                    echo "<script>alert('這個帳號已經存在了!請使用其他帳號註冊');history.go(-1);</script>";
                                    die;
                            }
    
  6. 再來開始處理註冊機器人的問題。這裡我們使用最單純的自己設定一個圖檔來處理,不過 PHP 繪圖,需要自己處理相關函式庫, 同時得要安裝 php-gd 模組才行!
    # yum install php-gd  (這裡要用 root 的權限)
    # systemctl restart httpd  (這裡要用 root 的權限)
    
    $ mkdir ~/www/images  (恢復 student 的權限)
    $ chmod 777  ~/www/images
    $ vim include/captcha.php
    <?php
    
    // 開始驗證碼 https://gnehcic.azurewebsites.net/php建立圖形驗證碼/
    $CaptchaString = "";    //驗證碼文字
    $CaptchaLength = 5;             //驗證碼長度
    
    //產生數字驗證碼
    for($i=0; $i < $CaptchaLength; $i++)
            $CaptchaString = $CaptchaString.rand(0,9);
    
    $_SESSION['CAPTCHA'] = $CaptchaString;  //驗證碼存入SESSION內
    
    $CaptchaWidth = 70;                                     //驗證碼影像寬度
    $CaptchaHeight = 20;                            //驗證碼影像高度
    
    //建立影像
    $Captcha = ImageCreate($CaptchaWidth, $CaptchaHeight);
    //設定背景顏色,範例是紅色
    $BackgroundColor = ImageColorAllocate($Captcha, 255, 0, 0);
    //設定文字顏色,範例是黑色
    $FontColor = ImageColorAllocate($Captcha, 0, 0, 0);
    //影像填滿背景顏色
    ImageFill($Captcha, 0, 0, $BackgroundColor);
    //影像畫上驗證碼
    ImageString($Captcha, 6, 14, 3, $_SESSION['CAPTCHA'] , $FontColor);
    //imagettftext($Captcha, 20, 0, 0, 0, $FontColor, 'Times', $_SESSION['CAPTCHA'] );
    //隨機畫上200個點,做為雜訊用
    for($i = 0; $i < 100; $i++) {
            Imagesetpixel($Captcha, rand() % $CaptchaWidth , rand() % $CaptchaHeight , $FontColor);
    }
    //輸出驗證碼影像
    $filename = sprintf( "./images/check.png", time());
    ImagePNG($Captcha, $filename);
    ImageDestroy($Captcha);
    
    ?>
    
    $ vim register.php
    	session_start();
    	include ('include/config.php');
    
            if ( isset ( $_REQUEST['action'] ) ) {
    		....
    	} else {
    		include ('include/captcha.php');
            }
    
    // 之後在 submit 的表單內,增加底下這個資料
                    <td colspan="3" style="text-align:center; ">
                            <img src="images/check.png" /><br />
                            <input type="text" name="checking" /><br />
                            <input type="hidden" name="action" value="reg" />
                            <input type="submit" value="送出註冊" />
                    </td>
    
  7. 再來就得要注意註冊時,得要先檢查這個驗證碼!驗證碼的數字已經記載在前一次填寫資料的 $_SESSION['CAPTCHA'] 這個 session 內, 所以,首先就得要處理這個項目的資料才行!這個項目如果不對,就直接丟回去前一頁囉!因此這樣做即可:
    $ vim register.php
    
            session_start();
            include ('include/config.php');
    
            if ( isset ( $_REQUEST['action'] ) ) {
                    if ( $_REQUEST['action'] == 'reg' ) {
                            // 先確認是否取得正確的註冊驗證碼
                            $checking    = $_REQUEST['checking'];
                            if ( $_SESSION['CAPTCHA'] != $checking ) {
                                    echo "<script>alert('驗證碼設定錯誤,請重新填寫註冊資料');history.go(-1);</script>";
                                    die;
                            }
    
                            // 先取得所需要的變數資料
    			....
    
Top
HOME