PHP 超级全局变量 详解

超级全局变量是PHP内置的特殊变量,在脚本的任何位置(包括函数和类内部)都可以直接访问,无需使用global关键字声明。

特点:从PHP 4.1.0开始引入,在所有作用域中自动可用,是PHP编程中的核心组件。

PHP 超级全局变量概述

PHP提供了9个内置的超级全局变量,它们在整个脚本执行期间都可用:

  • $GLOBALS
  • $_SERVER
  • $_REQUEST
  • $_POST
  • $_GET
  • $_FILES
  • $_ENV
  • $_COOKIE
  • $_SESSION

快速参考表

变量名 作用 作用域
$GLOBALS 引用全局作用域中的全部变量 全局
$_SERVER 服务器和执行环境信息 全局
$_REQUEST 收集HTML表单提交的数据 全局
$_POST 收集POST方法提交的表单数据 全局
$_GET 收集GET方法提交的表单数据和URL参数 全局
$_FILES 处理文件上传 全局
$_ENV 环境变量信息 全局
$_COOKIE HTTP Cookies信息 全局
$_SESSION 会话变量信息 全局

1. $GLOBALS 全局变量数组

$GLOBALS是一个包含了所有全局变量的数组,变量的名字就是数组的键。

基本用法实例:

<?php
// 定义两个全局变量
$x = 75;
$y = 25;

// 在函数内部访问全局变量
function addition() {
    // 使用$GLOBALS访问全局变量
    $GLOBALS['z'] = $GLOBALS['x'] + $GLOBALS['y'];
}

addition();
echo "计算结果: " . $z; // 输出: 100

// 遍历$GLOBALS数组
echo "<h4>当前所有全局变量:</h4>";
echo "<ul>";
foreach ($GLOBALS as $key => $value) {
    if (!is_array($value) && !is_object($value)) {
        echo "<li>$key = " . htmlspecialchars($value) . "</li>";
    }
}
echo "</ul>";
?>
注意:$GLOBALSglobal关键字的区别:
- $GLOBALS是一个数组,通过键名访问
- global是一个关键字,用于在函数内部引入全局变量
// 使用global关键字
function test() {
    global $x, $y;
    return $x + $y;
}

$_SERVER - 服务器和执行环境信息

$_SERVER包含了服务器信息、请求头和当前脚本的信息,由Web服务器创建。这些元素在不同的服务器环境(Apache、Nginx、IIS等)中可能有所不同。

完整的$_SERVER元素分类列表:

元素 描述 示例值
脚本位置和路径
$_SERVER['PHP_SELF'] 当前执行脚本的文件名,相对于文档根目录 /index.php
$_SERVER['SCRIPT_FILENAME'] 当前执行脚本的绝对路径 /var/www/html/index.php
$_SERVER['SCRIPT_NAME'] 包含当前脚本的路径 /index.php
$_SERVER['DOCUMENT_ROOT'] 当前运行脚本所在的文档根目录 /var/www/html
$_SERVER['PATH_TRANSLATED'] 文件系统基本路径(虚拟到真实路径映射) /var/www/html/index.php
服务器信息
$_SERVER['SERVER_NAME'] 服务器主机名 www.example.com
$_SERVER['SERVER_ADDR'] 服务器IP地址 192.168.1.1
$_SERVER['SERVER_PORT'] 服务器端口 80443
$_SERVER['SERVER_SOFTWARE'] 服务器标识字符串 Apache/2.4.41
$_SERVER['SERVER_PROTOCOL'] 请求协议名称和版本 HTTP/1.1
$_SERVER['SERVER_ADMIN'] 服务器管理员邮箱 admin@example.com
$_SERVER['SERVER_SIGNATURE'] 服务器版本和虚拟主机名 Apache/2.4.41
请求信息
$_SERVER['REQUEST_METHOD'] 请求方法(GET、POST等) GETPOST
$_SERVER['REQUEST_TIME'] 请求开始时的时间戳 1612345678
$_SERVER['REQUEST_TIME_FLOAT'] 请求开始时的时间戳(微秒精度) 1612345678.1234
$_SERVER['REQUEST_URI'] 请求的URI /index.php?page=1
$_SERVER['QUERY_STRING'] 查询字符串(如果有) page=1&sort=asc
$_SERVER['PATH_INFO'] 路径信息(如果有) /users/123
客户端信息
$_SERVER['REMOTE_ADDR'] 客户端IP地址 192.168.1.100
$_SERVER['REMOTE_HOST'] 客户端主机名 client.example.com
$_SERVER['REMOTE_PORT'] 客户端端口 54321
$_SERVER['REMOTE_USER'] 认证用户(如果使用HTTP认证) john
HTTP头信息
$_SERVER['HTTP_HOST'] Host头信息 www.example.com
$_SERVER['HTTP_USER_AGENT'] 用户代理字符串 Mozilla/5.0...
$_SERVER['HTTP_ACCEPT'] Accept头信息 text/html,application/xhtml+xml
$_SERVER['HTTP_ACCEPT_LANGUAGE'] Accept-Language头信息 en-US,en;q=0.9
$_SERVER['HTTP_ACCEPT_ENCODING'] Accept-Encoding头信息 gzip, deflate
$_SERVER['HTTP_REFERER'] Referer头信息(不一定可靠) https://google.com
$_SERVER['HTTP_CONNECTION'] Connection头信息 keep-alive
$_SERVER['HTTP_CACHE_CONTROL'] Cache-Control头信息 max-age=0
$_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'] Upgrade-Insecure-Requests头信息 1
$_SERVER['HTTP_COOKIE'] Cookie头信息 session_id=abc123
$_SERVER['HTTP_AUTHORIZATION'] Authorization头信息 Basic dXNlcjpwYXNz
HTTPS和SSL信息
$_SERVER['HTTPS'] 如果通过HTTPS访问则非空 on
$_SERVER['SSL_PROTOCOL'] SSL协议版本 TLSv1.2
$_SERVER['SSL_CIPHER'] SSL加密套件 ECDHE-RSA-AES256-GCM-SHA384
$_SERVER['SERVER_PORT_SECURE'] 安全端口标识 1
认证信息
$_SERVER['PHP_AUTH_USER'] HTTP认证用户名 admin
$_SERVER['PHP_AUTH_PW'] HTTP认证密码 secret123
$_SERVER['AUTH_TYPE'] 认证类型 Basic
其他重要元素
$_SERVER['GATEWAY_INTERFACE'] CGI规范版本 CGI/1.1
$_SERVER['CONTENT_LENGTH'] 请求内容长度 348
$_SERVER['CONTENT_TYPE'] 请求内容类型 application/x-www-form-urlencoded
$_SERVER['REDIRECT_STATUS'] 重定向状态 200
$_SERVER['REDIRECT_URL'] 重定向URL /new/location
$_SERVER['SCRIPT_URI'] 脚本的完整URI http://www.example.com/index.php
$_SERVER['REQUEST_SCHEME'] 请求方案(http或https) https
$_SERVER['ORIG_PATH_INFO'] 原始路径信息 /original/path

实用示例:查看所有$_SERVER元素

<?php
// 安全地显示所有$_SERVER元素
function displayServerInfo() {
    echo "<h4>完整的\$_SERVER数组内容:</h4>";
    echo "<div style='max-height: 400px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;'>";
    echo "<table class='table table-sm table-bordered'>";
    echo "<thead><tr><th>键名</th><th>值</th></tr></thead>";
    echo "<tbody>";

    // 按字母顺序排序
    ksort($_SERVER);

    foreach ($_SERVER as $key => $value) {
        // 安全过滤显示
        $safe_key = htmlspecialchars($key);
        $safe_value = htmlspecialchars(print_r($value, true));

        echo "<tr>";
        echo "<td style='font-family: monospace;'>\$_SERVER['$safe_key']</td>";
        echo "<td style='font-family: monospace; font-size: 12px;'><pre style='margin: 0;'>$safe_value</pre></td>";
        echo "</tr>";
    }

    echo "</tbody></table>";
    echo "</div>";

    // 统计信息
    echo "<p class='mt-3'><strong>总计:</strong> " . count($_SERVER) . " 个\$_SERVER元素</p>";
}

// 显示当前请求的基本信息
function displayCurrentRequest() {
    echo "<h4>当前请求信息:</h4>";
    echo "<ul>";

    // 获取基本信息
    $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'unknown';
    $uri = $_SERVER['REQUEST_URI'] ?? '/';
    $full_url = $protocol . '://' . $host . $uri;

    echo "<li><strong>完整URL:</strong> " . htmlspecialchars($full_url) . "</li>";
    echo "<li><strong>请求方法:</strong> " . ($_SERVER['REQUEST_METHOD'] ?? 'UNKNOWN') . "</li>";
    echo "<li><strong>客户端IP:</strong> " . ($_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN') . "</li>";
    echo "<li><strong>用户代理:</strong> " . ($_SERVER['HTTP_USER_AGENT'] ?? 'UNKNOWN') . "</li>";
    echo "<li><strong>脚本位置:</strong> " . ($_SERVER['SCRIPT_FILENAME'] ?? 'UNKNOWN') . "</li>";

    echo "</ul>";
}

// 执行显示函数
displayCurrentRequest();
displayServerInfo();

// 服务器环境检测
echo "<h4>服务器环境检测:</h4>";
echo "<ul>";

// 检测服务器软件
if (strpos($_SERVER['SERVER_SOFTWARE'] ?? '', 'Apache') !== false) {
    echo "<li>服务器: Apache</li>";
} elseif (strpos($_SERVER['SERVER_SOFTWARE'] ?? '', 'nginx') !== false) {
    echo "<li>服务器: Nginx</li>";
} elseif (strpos($_SERVER['SERVER_SOFTWARE'] ?? '', 'IIS') !== false) {
    echo "<li>服务器: IIS</li>";
} else {
    echo "<li>服务器: " . htmlspecialchars($_SERVER['SERVER_SOFTWARE'] ?? '未知') . "</li>";
}

// 检测PHP运行方式
if (PHP_SAPI === 'cli') {
    echo "<li>运行方式: CLI</li>";
} elseif (isset($_SERVER['GATEWAY_INTERFACE'])) {
    echo "<li>运行方式: CGI/FastCGI</li>";
} else {
    echo "<li>运行方式: Apache Module</li>";
}

// 检查是否通过代理
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    echo "<li>通过代理访问</li>";
    echo "<li>真实IP: " . htmlspecialchars($_SERVER['HTTP_X_FORWARDED_FOR']) . "</li>";
}

echo "</ul>";
?>

注意事项:

  • 服务器差异:不同的Web服务器(Apache、Nginx、IIS)提供的$_SERVER元素可能不同
  • 配置影响:PHP和服务器配置会影响可用的$_SERVER元素
  • 安全性:某些$_SERVER元素可能包含敏感信息,在生产环境中应谨慎显示
  • 可靠性:部分元素(如HTTP_REFERER)可能被客户端伪造,不应完全信任
  • 性能:频繁访问$_SERVER数组可能影响性能,建议缓存常用值

常用$_SERVER元素实用函数

<?php
/**
 * 获取当前页面的完整URL
 */
function getCurrentUrl() {
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
    $uri = $_SERVER['REQUEST_URI'] ?? '/';
    return $protocol . '://' . $host . $uri;
}

/**
 * 获取客户端真实IP地址(考虑代理)
 */
function getClientIp() {
    $ip_keys = [
        'HTTP_CLIENT_IP',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_X_CLUSTER_CLIENT_IP',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED',
        'REMOTE_ADDR'
    ];

    foreach ($ip_keys as $key) {
        if (isset($_SERVER[$key])) {
            $ip_list = explode(',', $_SERVER[$key]);
            foreach ($ip_list as $ip) {
                $ip = trim($ip);
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    return $ip;
                }
            }
        }
    }

    return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

/**
 * 检测是否为AJAX请求
 */
function isAjaxRequest() {
    return isset($_SERVER['HTTP_X_REQUESTED_WITH'])
        && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}

/**
 * 检测是否为HTTPS请求
 */
function isHttps() {
    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
        return true;
    }
    if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
        return true;
    }
    if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') {
        return true;
    }
    if ((isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) {
        return true;
    }
    return false;
}

/**
 * 获取当前脚本的目录路径
 */
function getScriptDirectory() {
    return dirname($_SERVER['SCRIPT_FILENAME']);
}

/**
 * 获取用户浏览器信息
 */
function getUserBrowser() {
    $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';

    if (strpos($user_agent, 'MSIE') !== false) return 'Internet Explorer';
    if (strpos($user_agent, 'Edge') !== false) return 'Microsoft Edge';
    if (strpos($user_agent, 'Chrome') !== false) return 'Google Chrome';
    if (strpos($user_agent, 'Firefox') !== false) return 'Mozilla Firefox';
    if (strpos($user_agent, 'Safari') !== false) return 'Apple Safari';
    if (strpos($user_agent, 'Opera') !== false) return 'Opera';

    return 'Unknown Browser';
}

// 使用示例
echo "<h4>实用信息:</h4>";
echo "<ul>";
echo "<li>当前URL: " . getCurrentUrl() . "</li>";
echo "<li>客户端IP: " . getClientIp() . "</li>";
echo "<li>是否AJAX请求: " . (isAjaxRequest() ? '是' : '否') . "</li>";
echo "<li>是否HTTPS: " . (isHttps() ? '是' : '否') . "</li>";
echo "<li>脚本目录: " . getScriptDirectory() . "</li>";
echo "<li>用户浏览器: " . getUserBrowser() . "</li>";
echo "</ul>";
?>

3. $_REQUEST - 获取请求数据

$_REQUEST默认包含了$_GET$_POST$_COOKIE的数据。

<?php
// 示例:处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 使用$_REQUEST获取数据(不推荐在生产环境中使用)
    $name = htmlspecialchars($_REQUEST['name'] ?? '');
    $email = htmlspecialchars($_REQUEST['email'] ?? '');

    echo "<h3>表单提交成功</h3>";
    echo "<p>姓名: $name</p>";
    echo "<p>邮箱: $email</p>";
}

// 同时处理GET和POST请求的示例
if (isset($_REQUEST['action'])) {
    $action = $_REQUEST['action'];
    echo "执行操作: " . htmlspecialchars($action);
}
?>
安全警告:由于$_REQUEST混合了多种来源的数据,可能存在安全风险。建议明确使用$_GET$_POST

4. $_POST - 获取POST请求数据

用于收集通过POST方法提交的表单数据,适合传输敏感信息。

完整表单示例:

<!DOCTYPE html>
<html>
<head>
    <title>用户注册</title>
</head>
<body>
    <h2>用户注册表单</h2>
    <form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>">
        <div>
            <label for="username">用户名:</label>
            <input type="text" id="username" name="username" required>
        </div>
        <div>
            <label for="email">邮箱:</label>
            <input type="email" id="email" name="email" required>
        </div>
        <div>
            <label for="password">密码:</label>
            <input type="password" id="password" name="password" required>
        </div>
        <button type="submit" name="submit">注册</button>
    </form>

    <?php
    if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['submit'])) {
        // 获取POST数据并处理
        $username = htmlspecialchars($_POST['username'] ?? '');
        $email = htmlspecialchars($_POST['email'] ?? '');
        $password = $_POST['password'] ?? '';

        echo "<h3>注册信息:</h3>";
        echo "<p>用户名: $username</p>";
        echo "<p>邮箱: $email</p>";

        // 在实际应用中,应该对密码进行哈希处理
        if (!empty($password)) {
            $hashed_password = password_hash($password, PASSWORD_DEFAULT);
            echo "<p>密码已加密存储</p>";
        }
    }
    ?>
</body>
</html>

5. $_GET - 获取GET请求数据

用于收集通过GET方法提交的数据,数据会显示在URL中。

<?php
// 处理URL参数:http://example.com?page=2&sort=date
if (isset($_GET['page'])) {
    $current_page = intval($_GET['page']);
    echo "当前页码: $current_page<br>";
}

if (isset($_GET['sort'])) {
    $sort_by = htmlspecialchars($_GET['sort']);
    echo "排序方式: $sort_by<br>";
}

// 构建带参数的链接示例
$base_url = "products.php";
$params = [
    'category' => 'electronics',
    'sort' => 'price',
    'page' => 2
];
$query_string = http_build_query($params);
$full_url = $base_url . '?' . $query_string;

echo "<a href='$full_url'>查看电子产品(第2页,按价格排序)</a>";
?>

6. $_FILES - 处理文件上传

用于处理通过表单上传的文件。

<?php
// 文件上传处理
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file'])) {
    $upload_dir = 'uploads/';
    $file_name = basename($_FILES['file']['name']);
    $file_tmp = $_FILES['file']['tmp_name'];
    $file_size = $_FILES['file']['size'];
    $file_type = $_FILES['file']['type'];
    $file_error = $_FILES['file']['error'];

    // 检查上传是否成功
    if ($file_error === UPLOAD_ERR_OK) {
        // 检查文件类型
        $allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
        if (in_array($file_type, $allowed_types)) {
            // 检查文件大小(限制为2MB)
            if ($file_size <= 2 * 1024 * 1024) {
                // 生成唯一文件名
                $new_filename = uniqid() . '_' . $file_name;
                $destination = $upload_dir . $new_filename;

                if (move_uploaded_file($file_tmp, $destination)) {
                    echo "文件上传成功!<br>";
                    echo "文件名: $new_filename<br>";
                    echo "文件大小: " . round($file_size / 1024, 2) . " KB<br>";
                    echo "文件类型: $file_type<br>";
                } else {
                    echo "文件移动失败!";
                }
            } else {
                echo "文件太大,最大允许2MB";
            }
        } else {
            echo "不支持的文件类型!";
        }
    } else {
        echo "上传错误: " . $file_error;
    }
}
?>

7. $_SESSION - 会话管理

用于在不同页面间存储用户会话数据。

<?php
// 启动会话
session_start();

// 登录处理
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['login'])) {
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';

    // 简单的验证(实际应从数据库验证)
    if ($username === 'admin' && $password === '123456') {
        $_SESSION['user_id'] = 1;
        $_SESSION['username'] = $username;
        $_SESSION['login_time'] = time();
        $_SESSION['is_admin'] = true;

        echo "登录成功!欢迎 $username";
    } else {
        echo "登录失败!";
    }
}

// 检查用户是否已登录
if (isset($_SESSION['user_id'])) {
    echo "<h4>当前会话信息:</h4>";
    echo "<ul>";
    echo "<li>用户ID: " . $_SESSION['user_id'] . "</li>";
    echo "<li>用户名: " . htmlspecialchars($_SESSION['username']) . "</li>";
    echo "<li>登录时间: " . date('Y-m-d H:i:s', $_SESSION['login_time']) . "</li>";
    echo "<li>管理员: " . ($_SESSION['is_admin'] ? '是' : '否') . "</li>";
    echo "</ul>";

    // 注销链接
    echo "<a href='logout.php'>退出登录</a>";
}

// 销毁会话(logout.php示例)
if (isset($_GET['action']) && $_GET['action'] == 'logout') {
    session_unset();    // 清除所有会话变量
    session_destroy();  // 销毁会话
    header('Location: index.php');
    exit();
}
?>

8. $_COOKIE - 处理Cookies

用于处理浏览器发送的Cookie数据。

<?php
// 设置Cookie
if (!isset($_COOKIE['visitor_count'])) {
    $count = 1;
    setcookie('visitor_count', $count, time() + 86400 * 30, '/'); // 30天过期
} else {
    $count = intval($_COOKIE['visitor_count']) + 1;
    setcookie('visitor_count', $count, time() + 86400 * 30, '/');
}

echo "访问次数: $count<br>";

// 设置用户偏好
if (isset($_POST['theme'])) {
    $theme = $_POST['theme'];
    setcookie('theme', $theme, time() + 86400 * 365, '/'); // 1年过期
    echo "主题已设置为: $theme";
}

// 读取Cookie
if (isset($_COOKIE['theme'])) {
    $current_theme = htmlspecialchars($_COOKIE['theme']);
    echo "当前主题: $current_theme<br>";
}

// 删除Cookie
if (isset($_GET['clear_cookie'])) {
    setcookie('visitor_count', '', time() - 3600, '/'); // 设置为过去时间
    echo "Cookie已清除";
}
?>

9. $_ENV - 环境变量

用于获取环境变量信息。

<?php
// 获取环境变量
echo "<h4>环境变量:</h4>";
echo "<ul>";

// 显示所有环境变量
foreach ($_ENV as $key => $value) {
    echo "<li>$key = " . htmlspecialchars($value) . "</li>";
}

echo "</ul>";

// 常用环境变量示例
if (isset($_ENV['DB_HOST'])) {
    echo "数据库主机: " . htmlspecialchars($_ENV['DB_HOST']) . "<br>";
}

// 使用getenv()函数也可以获取环境变量
$app_env = getenv('APP_ENV') ?: 'production';
echo "应用环境: $app_env<br>";
?>

超级全局变量使用最佳实践

安全建议:

  1. 始终验证和过滤用户输入
  2. 使用htmlspecialchars()防止XSS攻击
  3. 对敏感数据使用filter_var()函数过滤
  4. 避免直接使用$_REQUEST,明确指定$_GET$_POST
  5. 使用预处理语句防止SQL注入
  6. 对密码使用password_hash()进行哈希

性能优化:

  1. 只在需要时使用session_start()
  2. 及时销毁不再需要的会话数据
  3. 限制Cookie的大小和数量
  4. 合理设置Cookie的过期时间
  5. 避免在$_SESSION中存储大量数据

综合示例:用户注册系统

<?php
// config.php - 配置文件
session_start();

// 数据库配置(从环境变量获取)
$db_host = $_ENV['DB_HOST'] ?? 'localhost';
$db_name = $_ENV['DB_NAME'] ?? 'testdb';
$db_user = $_ENV['DB_USER'] ?? 'root';
$db_pass = $_ENV['DB_PASS'] ?? '';

// 连接数据库
try {
    $pdo = new PDO(
        "mysql:host=$db_host;dbname=$db_name;charset=utf8mb4",
        $db_user,
        $db_pass,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ]
    );
} catch (PDOException $e) {
    die("数据库连接失败: " . $e->getMessage());
}

// register.php - 用户注册
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 验证CSRF令牌
    if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
        die("CSRF令牌验证失败!");
    }

    // 获取并清理输入
    $username = filter_var($_POST['username'], FILTER_SANITIZE_STRING);
    $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
    $password = $_POST['password'];

    // 验证输入
    if (empty($username) || empty($email) || empty($password)) {
        $_SESSION['error'] = "所有字段都是必填的!";
        header('Location: register.php');
        exit();
    }

    // 验证邮箱格式
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $_SESSION['error'] = "邮箱格式不正确!";
        header('Location: register.php');
        exit();
    }

    // 检查用户名是否已存在
    $stmt = $pdo->prepare("SELECT id FROM users WHERE username = ? OR email = ?");
    $stmt->execute([$username, $email]);

    if ($stmt->rowCount() > 0) {
        $_SESSION['error'] = "用户名或邮箱已存在!";
        header('Location: register.php');
        exit();
    }

    // 哈希密码
    $hashed_password = password_hash($password, PASSWORD_DEFAULT);

    // 插入用户数据
    $stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");

    if ($stmt->execute([$username, $email, $hashed_password])) {
        $_SESSION['success'] = "注册成功!请登录。";
        $_SESSION['user_id'] = $pdo->lastInsertId();
        $_SESSION['username'] = $username;

        // 设置记住我Cookie
        if (isset($_POST['remember_me'])) {
            $token = bin2hex(random_bytes(32));
            setcookie('remember_token', $token, time() + 86400 * 30, '/', '', true, true);

            // 将token存入数据库
            $stmt = $pdo->prepare("UPDATE users SET remember_token = ? WHERE id = ?");
            $stmt->execute([hash('sha256', $token), $_SESSION['user_id']]);
        }

        header('Location: dashboard.php');
        exit();
    } else {
        $_SESSION['error'] = "注册失败,请重试!";
        header('Location: register.php');
        exit();
    }
}
?>