首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP + AJAX 驗證碼驗證用戶登入:無刷新體驗完整實作

     編輯:PHP 綜合知識

前言

傳統登入需跳轉頁面,體驗不佳。結合 AJAX + 驗證碼 + Session,可實現無刷新登入、驗證失敗即時回饋、驗證碼自動更新。本文提供三檔案完整架構:驗證碼產生、前端頁面、後端驗證。

檔案架構

  • yz.php:驗證碼圖片產生器,將碼存入 $_SESSION['VCODE']
  • index.php:登入表單 (HTML + JS),AJAX 送驗證
  • loginCheck.php:後端驗證邏輯,回傳 ok 或 no

1. yz.php - 驗證碼產生

<?php
session_start();

header('Content-Type: image/png');

$width = 44;
$height = 18;
$length = 4;

$img = imagecreate($width, $height);

// 背景
$bg = imagecolorallocate($img, 245, 245, 245);
imagefill($img, 0, 0, $bg);

// 干擾像素
for ($i = 0; $i < 100; $i++) {
    $color = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
    imagesetpixel($img, rand() % 70, rand() % 30, $color);
}

// 產生 4 位數字
$code = '';
for ($i = 0; $i < $length; $i++) {
    $num = rand(1, 9);
    $code .= $num;
    $color = imagecolorallocate($img, rand(100, 255), rand(0, 100), rand(100, 255));
    imagestring($img, 5, 2 + $i * 10, 1, $num, $color);
}

// 存入 Session (關鍵:供 loginCheck.php 比對)
$_SESSION['VCODE'] = $code;

imagepng($img);
imagedestroy($img);

2. index.php - 前端登入頁

<!DOCTYPE html>
<html>
<head>
    <meta charset="gb2312">
    <title>管理後台登入</title>
    <style>
        body { background: url(./images/w2.jpg) center fixed no-repeat; font-family: 微軟正黑體; }
        #main { margin-top: 150px; text-align: center; font-size: 14px; }
        table { margin: 0 auto; }
        input { margin: 0 5px; padding: 5px; }
        #vcode { cursor: pointer; vertical-align: middle; }
    </style>
    <script src="./js/trim.js"></script>
    <script>
    // 清空驗證碼輸入框
    function clearCode() {
        document.getElementById('authCode').value = '';
    }
    
    // 更新驗證碼圖片
    function refreshCode() {
        var img = document.getElementById('vcode');
        img.src = 'yz.php?nocache=' + Date.now();
    }
    
    // 建立 XMLHttpRequest (相容 IE6+)
    function createXHR() {
        if (window.XMLHttpRequest) return new XMLHttpRequest();
        try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
        try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
        return null;
    }
    
    var xhr = createXHR();
    
    // AJAX 登入驗證
    function doLogin() {
        var user = trim(document.getElementById('username').value);
        var pass = trim(document.getElementById('password').value);
        var code = trim(document.getElementById('authCode').value);
        
        if (!user || !pass || !code) {
            alert('請輸入帳號、密碼、驗證碼!');
            return;
        }
        
        if (!xhr) {
            alert('瀏覽器不支援 AJAX');
            return;
        }
        
        var params = 'username=' + encodeURIComponent(user) +
                     '&password=' + encodeURIComponent(pass) +
                     '&authCode=' + encodeURIComponent(code) +
                     '&fresh=' + Math.random(); // 破解快取
        
        xhr.open('POST', 'loginCheck.php', true);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.send(params);
        
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200) {
                var result = xhr.responseText.trim();
                if (result === 'ok') {
                    window.location.href = 'adminCenter.php';
                } else {
                    alert('帳號、密碼或驗證碼錯誤!');
                    document.getElementById('username').focus();
                    refreshCode(); // 失敗自動換碼
                }
            }
        };
    }
    </script>
</head>
<body onload="document.getElementById('username').focus()">
    <div id="main">
        <table>
            <tr>
                <td>帳號:</td>
                <td><input type="text" id="username"></td>
                <td>密碼:</td>
                <td><input type="password" id="password"></td>
                <td>驗證碼:</td>
                <td><input type="text" id="authCode" size="6" maxlength="4" value="驗證碼" onfocus="clearCode()"></td>
                <td><img id="vcode" src="yz.php" alt="看不清?點擊換一張" onclick="refreshCode()"></td>
                <td><button onclick="doLogin()">登入</button></td>
            </tr>
        </table>
    </div>
</body>
</html>

3. loginCheck.php - 後端驗證

<?php
session_start();
require_once '../conn/connDB.php'; // 資料庫連線

$username = $_POST['username'] ?? '';
$password = md5($_POST['password'] ?? ''); // 實務請用 password_hash()
$authCode = $_POST['authCode'] ?? '';

$result = 'no';

// 1. 驗證碼比對 (Server 端比對,安全)
if (strtoupper($authCode) === strtoupper($_SESSION['VCODE'] ?? '')) {
    // 2. 資料庫查詢
    $sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
    $res = mysql_query($sql); // 實務請用 PDO + Prepared Statement
    
    if (mysql_num_rows($res) === 1) {
        $result = 'ok';
        $_SESSION['admin'] = true; // 標記登入狀態
    }
}

echo $result;

關鍵安全性說明

風險點本範例做法生產環境建議
SQL 注入直接拼接字串PDO + Prepared Statement
密碼儲存MD5 (已淘汰)password_hash() / password_verify()
驗證碼強度4 位純數字英數混合、干擾線、或 reCAPTCHA/hCaptcha
暴力破解無防禦IP 限流、帳號鎖定、雙因子認證
CSRF無 Token表單隱藏 CSRF Token、SameSite Cookie
HTTPS明文傳輸全站強制 HTTPS

現代化改寫建議 (Fetch + JSON)

// index.php 現代化版本
async function doLogin() {
    const formData = new FormData(document.getElementById('loginForm'));
    formData.append('fresh', Date.now());
    
    try {
        const res = await fetch('loginCheck.php', {
            method: 'POST',
            body: formData,
            credentials: 'same-origin' // 攜帶 Session Cookie
        });
        
        const result = await res.text();
        if (result === 'ok') {
            location.href = 'adminCenter.php';
        } else {
            alert('登入失敗');
            refreshCode();
        }
    } catch (e) {
        console.error(e);
        alert('網路錯誤');
    }
}

總結

AJAX 登入核心流程:前端攔截提交 → 發送帳密碼 → 後端驗證碼比對 → 資料庫查詢 → 回傳結果 → 前端決定跳轉或換碼。本範例展示傳統 XMLHttpRequest 寫法,現代專案建議改用 fetch() + FormData,並務必強化資料庫查詢、密碼儲存、傳輸加密等安全面向。


延伸閱讀:PHP 密碼雜湊最佳實踐、AJAX 登入完整指南、Web 安全:防禦 SQL 注入與 XSS

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved