当前位置: 首页 > news >正文

第十一章-PHP表单传值

第十一章-PHP表单传值

一,核心概念

1. 表单的基本结构(HTML)

通过HTML的<form>标签定义表单,关键属性包括:

  • action: 指定处理表单数据的PHP脚本路径(如action="process.php")。
  • method: 定义数据传输方式,常用GETPOST
<form action="process.php" method="post"><input type="text" name="username"><input type="password" name="password"><input type="submit" value="提交">
</form>

2. PHP接收表单数据的超全局变量

PHP通过预定义超全局变量获取表单数据:

  • $_GET: 接收通过method="get"提交的数据(数据附加在URL中)。
  • $_POST: 接收通过method="post"提交的数据(数据通过HTTP请求体传输)。
  • $_REQUEST: 合并了$_GET$_POST$_COOKIE的数据(不推荐,因安全性低)。
示例:获取数据
// 通过POST获取表单字段
$username = $_POST['username'];
$password = $_POST['password'];

3. GET vs POST的区别

3.1 底层原理
  • GET请求
    • 数据通过URL参数传输,如 process.php?name=John&age=25
    • 浏览器历史记录和服务器日志会保存完整URL。
  • POST请求
    • 数据在HTTP请求体中传输,不可见。
    • 适用于敏感操作(如修改数据库)。
3.2 使用场景扩展
  • GET的典型场景
    • 搜索引擎关键词传递:search.php?q=keyword
    • 分页导航:articles.php?page=2
  • POST的典型场景
    • 用户注册、登录、支付操作。
    • 上传文件或提交大型文本(如博客文章)。
特性GETPOST
数据位置URL参数(可见)HTTP请求体(不可见)
数据长度限制受URL长度限制(约2048字符)无限制(服务器配置可能限制)
安全性不适合敏感数据(如密码)相对更安全
缓存/书签可缓存、可收藏为书签不可缓存
典型用途搜索、分页等非敏感操作登录、注册、文件上传

4. 安全性注意事项

  • 过滤输入:始终验证和清理用户输入,避免SQL注入、XSS攻击。

    $username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
    
  • 防止CSRF:使用令牌(Token)验证请求来源。

  • 文件上传:需设置enctype="multipart/form-data",并通过$_FILES处理。


5. 完整示例

HTML表单(form.html):
<form action="process.php" method="post">邮箱:<input type="email" name="email">密码:<input type="password" name="password"><input type="submit" value="登录">
</form>
PHP处理脚本(process.php):
if ($_SERVER['REQUEST_METHOD'] === 'POST') {$email = $_POST['email'];$password = $_POST['password'];// 简单验证if (!empty($email) && !empty($password)) {echo "登录成功!邮箱:$email";} else {echo "请填写所有字段!";}
}

6. 其他传值方式

  • 文件上传:使用$_FILES处理。
  • 隐藏字段<input type="hidden" name="id" value="123">传递隐藏数据。
  • Session/Cookie:结合$_SESSION$_COOKIE管理用户状态。

二,表单传值方式

1. 基础传值方式

(1) GET 方法
  • 特点

    • 数据通过URL参数传递(如 ?key1=value1&key2=value2)。
    • 数据可见、长度受限(约2048字符)。
    • 可缓存、可书签保存。
  • 适用场景

    • 搜索、分页、筛选等非敏感操作。
  • 示例

    <form action="search.php" method="get"><input type="text" name="keyword"><input type="submit" value="搜索">
    </form>
    
    // PHP获取数据
    $keyword = $_GET['keyword'];
    
(2) POST 方法
  • 特点

    • 数据通过HTTP请求体传输,不可见。
    • 无长度限制(受服务器配置影响)。
    • 不可缓存,适合敏感操作。
  • 适用场景

    • 用户登录、注册、文件上传等。
  • 示例

    <form action="login.php" method="post"><input type="text" name="username"><input type="password" name="password"><input type="submit" value="登录">
    </form>
    
    $username = $_POST['username'];
    $password = $_POST['password'];
    

2. 扩展传值方式

(1) 隐藏字段(Hidden Fields)
  • 用途

    • 传递无需用户填写但后端需要的数据(如用户ID、令牌)。
  • 示例

    <form action="update.php" method="post"><input type="hidden" name="user_id" value="123"><input type="text" name="new_email"><input type="submit" value="更新邮箱">
    </form>
    
    $user_id = $_POST['user_id'];
    
(2) 文件上传(File Upload)
  • 特点

    • 需设置表单的 enctype="multipart/form-data"
    • 通过 $_FILES 超全局数组处理文件。
  • 示例

    <form action="upload.php" method="post" enctype="multipart/form-data"><input type="file" name="avatar"><input type="submit" value="上传头像">
    </form>
    
    $file_name = $_FILES['avatar']['name'];
    $tmp_path = $_FILES['avatar']['tmp_name'];
    move_uploaded_file($tmp_path, "uploads/$file_name");
    

3. 高级传值技术

(1) AJAX 异步传值
  • 用途

    • 不刷新页面提交数据,提升用户体验。
  • 示例(使用JavaScript Fetch API)

    // 前端代码
    document.getElementById('myForm').addEventListener('submit', function(e) {e.preventDefault();const formData = new FormData(this);fetch('api/save.php', {method: 'POST',body: formData}).then(response => response.json()).then(data => console.log(data));
    });
    
    // PHP返回JSON响应
    header('Content-Type: application/json');
    echo json_encode(['status' => 'success']);
    
(2) Session 和 Cookie
  • Session

    • 服务器端存储用户状态,通过 $_SESSION 访问。
    session_start();
    $_SESSION['user_id'] = 123; // 存储
    $userId = $_SESSION['user_id']; // 读取
    
  • Cookie

    • 客户端存储数据,通过 $_COOKIE 访问。
    setcookie('theme', 'dark', time() + 3600); // 设置
    $theme = $_COOKIE['theme']; // 读取
    

4. RESTful API 传值方式

(1) HTTP 方法扩展
  • PUT/DELETE

    • 用于更新或删除资源(需通过AJAX或框架模拟)。
    // 伪代码:通过POST模拟PUT
    if ($_POST['_method'] === 'PUT') {// 处理更新逻辑
    }
    
(2) JSON 数据传值
  • 前端发送JSON

    fetch('api/users', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ name: 'John', age: 30 })
    });
    
  • PHP接收JSON

    $data = json_decode(file_get_contents('php://input'), true);
    $name = $data['name'];
    

5. 安全性对比与选择建议

传值方式安全性适用场景注意事项
GET公开数据查询避免传递敏感信息
POST表单提交、敏感操作结合HTTPS使用
Session用户登录状态、跨页面数据共享及时销毁Session防止会话固定
Cookie客户端偏好设置避免存储敏感数据
AJAX/JSON前后端分离、API交互需验证来源和CORS配置

6. 最佳实践

  1. 始终验证输入

    $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
    if (!$email) die("邮箱格式无效");
    
  2. 防范CSRF

    // 生成Token
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    // 表单中嵌入
    <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
    // 验证Token
    if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) die("非法请求");
    
  3. 使用HTTPS

    • 对敏感数据传输强制启用HTTPS。

三,接收数据方式

1. 基础数据接收方式

(1) 通过 $_GET 接收URL参数
  • 场景:处理 method="get" 表单或URL中的查询参数(如 ?id=123)。

  • 示例

    // URL: example.com?name=John&age=25
    $name = $_GET['name'] ?? '未填写姓名'; // 使用空合并运算符避免未定义错误
    $age = filter_input(INPUT_GET, 'age', FILTER_VALIDATE_INT); // 过滤并验证为整数
    
(2) 通过 $_POST 接收表单数据
  • 场景:处理 method="post" 的表单提交。

  • 示例

    // 表单字段:<input type="text" name="email">
    $email = $_POST['email'] ?? '';
    // 使用过滤器验证邮箱格式
    $email = filter_var($email, FILTER_VALIDATE_EMAIL);
    if (!$email) {die("邮箱格式无效");
    }
    
(3) 通过 $_REQUEST 接收混合数据
  • 注意$_REQUEST 合并了 $_GET$_POST$_COOKIE,但不推荐使用(安全性低,优先级不可控)。

  • 示例

    $data = $_REQUEST['key']; // 可能来自GET、POST或COOKIE
    

2. 复杂数据接收方式

(1) 接收数组数据
  • 场景:表单中多选框(Checkboxes)或同名字段。

  • HTML示例

    <input type="checkbox" name="hobbies[]" value="reading"> 阅读
    <input type="checkbox" name="hobbies[]" value="sports"> 运动
    
  • PHP处理

    $hobbies = $_POST['hobbies'] ?? [];
    if (!empty($hobbies)) {foreach ($hobbies as $hobby) {echo htmlspecialchars($hobby); // 转义输出防止XSS}
    }
    
(2) 接收文件数据($_FILES
  • 场景:文件上传表单(需设置 enctype="multipart/form-data")。

  • HTML示例

    <form action="upload.php" method="post" enctype="multipart/form-data"><input type="file" name="file_upload">
    </form>
    
  • PHP处理

    $file = $_FILES['file_upload'];
    if ($file['error'] === UPLOAD_ERR_OK) {$tmp_name = $file['tmp_name'];$target_path = "uploads/" . basename($file['name']);move_uploaded_file($tmp_name, $target_path);
    }
    
(3) 接收JSON数据
  • 场景:前端通过AJAX发送JSON格式数据(如API请求)。

  • PHP处理

    $json_data = file_get_contents('php://input'); // 读取原始输入流
    $data = json_decode($json_data, true); // 转换为关联数组
    if (json_last_error() !== JSON_ERROR_NONE) {die("JSON解析失败");
    }
    $username = $data['username'] ?? '';
    

3. 安全性处理

(1) 输入过滤与验证
  • 推荐函数filter_input()filter_var()

  • 示例

    // 过滤并验证整数
    $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
    if ($id === false || $id < 1) {die("ID无效");
    }// 清理字符串(移除标签和空格)
    $comment = filter_input(INPUT_POST, 'comment', FILTER_SANITIZE_STRING);
    $comment = trim($comment);
    
(2) 防止SQL注入
  • 使用预处理语句(PDO示例)

    $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
    $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
    $stmt->execute(['email' => $_POST['email']]);
    $user = $stmt->fetch();
    
(3) 防止跨站请求伪造(CSRF)
  • 生成并验证Token

    session_start();
    // 生成Token
    if (empty($_SESSION['csrf_token'])) {$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    // 表单中嵌入Token
    <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
    // 验证Token
    if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {die("非法请求");
    }
    

4. 其他数据接收方式

(1) 命令行参数($argv$argc
  • 场景:PHP CLI(命令行界面)脚本接收参数。

  • 示例

    php script.php arg1 arg2
    
    // script.php
    print_r($argv); // 输出:Array([0] => script.php, [1] => arg1, [2] => arg2)
    
(2) 接收HTTP头部信息(getallheaders()$_SERVER
  • 场景:获取请求头信息(如认证Token)。

  • 示例

    $headers = getallheaders();
    $auth_token = $headers['Authorization'] ?? '';
    
(3) 处理PUT/DELETE请求
  • 场景:RESTful API中处理非POST请求。

  • 示例

    if ($_SERVER['REQUEST_METHOD'] === 'PUT') {parse_str(file_get_contents('php://input'), $put_data);$id = $put_data['id'];// 处理更新逻辑
    }
    

5. 最佳实践总结

  1. 始终检查变量是否存在

    // 使用 isset() 或空合并运算符
    $value = $_POST['key'] ?? 'default';
    
  2. 优先使用过滤器函数

    $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
    
  3. 避免直接使用未过滤的数据

    // 错误示例(易受XSS攻击)
    echo $_GET['content'];
    // 正确做法
    echo htmlspecialchars($_GET['content']);
    
  4. 严格限制文件上传类型和大小

    $allowed_types = ['image/jpeg', 'image/png'];
    if (!in_array($_FILES['file']['type'], $allowed_types)) {die("只允许上传JPEG和PNG图片");
    }
    

四,PHP处理复选框

1. HTML复选框基础

1.1 正确命名复选框
  • 关键点:使用数组形式命名(name="字段名[]"),以便PHP接收多个值。

  • 示例

    <form action="process.php" method="post"><input type="checkbox" name="hobbies[]" value="reading"> 阅读<input type="checkbox" name="hobbies[]" value="coding"> 编程<input type="checkbox" name="hobbies[]" value="sports"> 运动<input type="submit" value="提交">
    </form>
    
1.2 动态生成复选框
  • 场景:从数据库或配置中加载选项。

  • PHP动态生成示例

    $allowedHobbies = ['reading', 'coding', 'sports', 'music'];
    foreach ($allowedHobbies as $hobby) {echo '<input type="checkbox" name="hobbies[]" value="' . htmlspecialchars($hobby) . '"> ' . $hobby;
    }
    

2. PHP接收复选框数据

2.1 接收数组数据
  • 使用 $_POST$_GET

    $selectedHobbies = $_POST['hobbies'] ?? [];
    
    • 若用户未勾选任何复选框,$_POST['hobbies'] 将不存在,需用空合并运算符 (??) 避免错误。
2.2 验证与过滤数据
  • 检查是否为数组

    if (!is_array($selectedHobbies)) {die("非法请求");
    }
    
  • 过滤非法值

    $allowedValues = ['reading', 'coding', 'sports', 'music'];
    $validHobbies = array_intersect($selectedHobbies, $allowedValues);
    if (count($validHobbies) === 0) {die("请至少选择一个有效兴趣");
    }
    

3. 安全性处理

3.1 防止XSS攻击
  • 转义输出

    foreach ($validHobbies as $hobby) {echo htmlspecialchars($hobby, ENT_QUOTES, 'UTF-8');
    }
    
3.2 防止SQL注入
  • 预处理语句示例(PDO)

    $stmt = $pdo->prepare("INSERT INTO user_hobbies (user_id, hobby) VALUES (:user_id, :hobby)");
    foreach ($validHobbies as $hobby) {$stmt->execute(['user_id' => $userId,'hobby' => $hobby]);
    }
    

4. 常见问题与解决方案

问题1:只接收到最后一个值
  • 原因:复选框未使用数组命名(如 name="hobby")。
  • 解决:确保命名格式为 name="字段名[]"
问题2:未选中时报错 Undefined index
  • 原因:直接访问 $_POST['hobbies'] 而未检查是否存在。

  • 解决:使用空合并运算符或 isset()

    $selectedHobbies = isset($_POST['hobbies']) ? $_POST['hobbies'] : [];
    
问题3:动态生成的选项被篡改
  • 场景:用户提交了不在允许列表中的值。
  • 解决:通过 array_intersect() 过滤非法值(见2.2节)。

5. 完整示例

HTML表单(form.html
<form action="process.php" method="post"><fieldset><legend>选择你的兴趣:</legend><?php$hobbies = ['reading' => '阅读', 'coding' => '编程', 'sports' => '运动'];foreach ($hobbies as $value => $label) {echo '<label><input type="checkbox" name="hobbies[]" value="' . htmlspecialchars($value) . '"> ' . htmlspecialchars($label) . '</label><br>';}?></fieldset><input type="submit" value="提交">
</form>
PHP处理脚本(process.php
<?php
// 1. 接收数据并验证
$selectedHobbies = $_POST['hobbies'] ?? [];
if (!is_array($selectedHobbies)) {die("非法请求");
}// 2. 过滤合法值
$allowedHobbies = ['reading', 'coding', 'sports'];
$validHobbies = array_intersect($selectedHobbies, $allowedHobbies);
if (empty($validHobbies)) {die("请至少选择一个兴趣");
}// 3. 安全存储到数据库(示例)
try {$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$stmt = $pdo->prepare("INSERT INTO user_hobbies (user_id, hobby) VALUES (?, ?)");foreach ($validHobbies as $hobby) {$stmt->execute([1, $hobby]); // 假设用户ID为1}echo "保存成功!选择的兴趣:" . implode(', ', $validHobbies);
} catch (PDOException $e) {die("数据库错误:" . $e->getMessage());
}

6. 高级应用

6.1 将数据存储为JSON
  • 场景:单个字段存储多个选项(非关系型数据)。

  • 示例

    $hobbiesJson = json_encode($validHobbies);
    // 存入数据库
    $stmt = $pdo->prepare("UPDATE users SET hobbies = ? WHERE id = ?");
    $stmt->execute([$hobbiesJson, $userId]);
    
6.2 回显已选中的复选框
  • 场景:编辑表单时显示用户之前的选择。

  • 示例

    $userHobbies = ['reading', 'sports']; // 从数据库读取
    foreach ($allowedHobbies as $value => $label) {$checked = in_array($value, $userHobbies) ? 'checked' : '';echo '<input type="checkbox" name="hobbies[]" value="' . $value . '" ' . $checked . '> ' . $label;
    }
    

项目示例:留言管理系统

1. 项目结构

 public/├── index.php        # 表单页面 & 处理结果└── style.css        # 一点简单样式

2. 代码

2.1 public/index.php
<?php
/*** index.php — 简易留言板 Demo** 运行方式(任选其一):*   1) PHP 内置服务器:php -S localhost:8000 -t .*   2) Docker:docker run -it --rm -p 8000:80 -v "$PWD":/var/www/html php:8.3-apache** 生产环境注意:*   - 请添加 CSRF token、防爆破、验证码等安全措施*   - 若要写数据库,请使用 PDO 并开启预处理防止 SQL 注入*   - 推荐使用 PRG 模式避免重复提交*//* ---------- 0) 初始化 ---------- */// 开启 Session(如果后续要加 CSRF,可在此使用)
// session_start();// 设置默认时区,防止 date() 提示 warning
date_default_timezone_set('Asia/Shanghai');// 统一输出编码(部分低版本 PHP CLI 默认 ISO-8859-1)
ini_set('default_charset', 'UTF-8');// 定义变量以便模板区直接使用
$result = null;
$error  = null;/* ---------- 1) 业务逻辑:仅在 POST 时处理 ---------- */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {// 使用 null 合并运算符防 Notice$name    = trim($_POST['name']    ?? '');$message = trim($_POST['message'] ?? '');// ---- (1) 基础验证 ----if ($name === '' || $message === '') {$error = '姓名和留言内容均不能为空!';} elseif (mb_strlen($name, 'UTF-8') > 30) {$error = '姓名请控制在 30 个字符以内!';} else {// ---- (2) 业务存储 / 发送邮件 / 写日志 ----// ★此处仅做演示;若要入库请使用 PDO + prepared statement$result = ['name'    => htmlspecialchars($name,    ENT_QUOTES, 'UTF-8'),'message' => htmlspecialchars($message, ENT_QUOTES, 'UTF-8'),'time'    => date('Y-m-d H:i:s'),'ip'      => $_SERVER['REMOTE_ADDR'] ?? 'unknown',];// ---- (3) 若用 PRG,取消注释下面两行 ----// $_SESSION['flash'] = $result; // 存 flash 数据// header('Location: '.$_SERVER['PHP_SELF']); exit;}
}/* ---------- 2) 取回 flash 数据(如果采用了 PRG) ---------- */
// if (isset($_SESSION['flash'])) {
//     $result = $_SESSION['flash'];
//     unset($_SESSION['flash']);
// }
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>PHP 表单传值 Demo</title><link rel="stylesheet" href="style.css"><!-- 基础安全请求头,可按需调整 --><?phpheader('X-Frame-Options: SAMEORIGIN');header("Content-Security-Policy: default-src \'self\'");?>
</head>
<body><h1>留言板(示例)</h1><!-- ---------- 3) 结果区 ---------- --><?php if ($result): ?><section class="success"><h2>提交成功!</h2><p><strong><?= $result['name'] ?></strong><?= $result['time'] ?> 留言:</p><!-- nl2br 把换行转换为 <br>;white-space:pre-wrap 在 CSS 里也能实现 --><blockquote><?= nl2br($result['message']) ?></blockquote><small>IP<?= $result['ip'] ?></small></section><?php elseif ($error): ?><section class="error"><?= $error ?></section><?php endif; ?><!-- ---------- 4) 表单区 ---------- --><form action="" method="post" autocomplete="off"><label>姓名:<input type="text"name="name"maxlength="30"requiredvalue="<?= isset($name) ? htmlspecialchars($name, ENT_QUOTES, 'UTF-8') : '' ?>"></label><label>留言:<textarea name="message"rows="5"required><?= isset($message) ? htmlspecialchars($message, ENT_QUOTES, 'UTF-8') : '' ?></textarea></label><button type="submit">提交</button></form>
</body>
</html>
2.2 public/style.css
body{font-family:system-ui, sans-serif;max-width:680px;margin:40px auto;padding:0 1rem;line-height:1.6}
h1{margin-bottom:1rem}
form{display:flex;flex-direction:column;gap:1rem}
label{display:flex;flex-direction:column;font-weight:600}
input,textarea{font:inherit;padding:.5rem;border:1px solid #ccc;border-radius:6px}
button{padding:.6rem 1.2rem;border:none;border-radius:6px;cursor:pointer;background:#007aff;color:#fff;font-weight:600}
button:hover{opacity:.9}
.success, .error{padding:1rem;border-radius:6px;margin-bottom:1rem}
.success{background:#e8f9e9;border:1px solid #4caf50}
.error{background:#ffeef0;border:1px solid #f44336}
blockquote{margin:.5rem 0;padding-left:1rem;border-left:4px solid #ccc;font-style:italic;white-space:pre-wrap}

相关文章:

  • Tauri窗口与界面管理:打造专业桌面应用体验 (入门系列五)
  • java面向对象编程【高级篇】之多态
  • 996引擎-人物模型(UIModel):创建内观时装备偏移问题
  • 【合新通信】---Mini单路光模块(Mini SFF/USOT)
  • tsconfig.json和tsconfig.node.json和tsconfig.app.json有什么区别
  • 公网域名如何解析到内网ip服务器?自己域名映射外网访问
  • Linux:基础IO 文件系统
  • [SystemVerilog] Struct
  • ChatGPT与DeepSeek在科研论文撰写中的整体科研流程与案例解析
  • 使用 malloc 函数模拟开辟一个 3x5 的整型二维数组
  • 多模态大语言模型arxiv论文略读(四十四)
  • linux blueZ 第六篇:嵌入式与工业级应用案例——在 Raspberry Pi、Yocto 与 Buildroot 上裁剪 BlueZ 并落地实战
  • 单例模式:确保类的唯一实例
  • MyBatis 类型处理器(TypeHandler)注册与映射机制:JsonListTypeHandler和JsonListTypeHandler注册时机
  • 单例模式:全局唯一性在软件设计中的艺术实践
  • 《代码整洁之道》第6章 对象和数据结构 - 笔记
  • 04 Enhanced Telecom Operations Map (eTOM)
  • 计算机网络自顶向下思维导图
  • 《代码整洁之道》第12章 迭进 - 笔记
  • EasyRTC嵌入式音视频通信SDK助力视频客服,开启智能服务新时代
  • 央行副行长:研究建立民营中小企业增信制度,破解民营中小企业信用不足等融资制约
  • 恒瑞医药赴港上市获证监会备案,拟发行不超8.15亿股
  • 持续更新丨伊朗港口爆炸事件已致406人受伤
  • 强政神鸟——故宫里的乌鸦
  • 百台新车首秀上海车展,跨国车企联手中国技术开启智能化下半场
  • 河南省鹤壁市人大常委会副主任李杰接受审查调查