GET和POST方法
学习目标
- 理解HTTP GET和POST方法的区别和应用场景
- 掌握PHP中处理GET和POST请求的方法
- 学会正确选择合适的HTTP方法
- 了解安全性考虑和最佳实践
HTTP方法概述
HTTP协议定义了多种请求方法,其中最常用的是GET和POST。这两种方法在Web开发中用于向服务器发送数据。
GET方法
GET方法用于从服务器获取数据,其特点包括:
- 数据通过URL参数传递
- 有数据长度限制(通常2048字符)
- 可以被浏览器缓存
- 可以被收藏为书签
- 不适合传输敏感信息
POST方法
POST方法用于向服务器提交数据,其特点包括:
- 数据通过HTTP请求体传递
- 没有数据长度限制
- 不会被浏览器缓存
- 不能被收藏为书签
- 适合传输敏感信息
PHP中的超全局变量
PHP提供了两个重要的超全局变量来处理HTTP请求数据:
$_GET 超全局变量
包含通过GET方法传递的所有参数:
<?php
// 获取单个参数
$name = $_GET['name'];
// 检查参数是否存在
if (isset($_GET['name'])) {
$name = $_GET['name'];
}
// 安全获取参数(带默认值)
$name = isset($_GET['name']) ? $_GET['name'] : 'Guest';
// 使用null合并运算符(PHP 7+)
$name = $_GET['name'] ?? 'Guest';
?>
$_POST 超全局变量
包含通过POST方法传递的所有参数:
<?php
// 获取POST数据
$username = $_POST['username'];
$password = $_POST['password'];
// 检查表单是否提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 处理表单数据
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
}
?>
GET方法详解
基本用法
<!-- HTML表单使用GET方法 -->
<form action="search.php" method="get">
<label for="query">搜索:</label>
<input type="text" id="query" name="query" placeholder="输入搜索关键词">
<button type="submit">搜索</button>
</form>
<?php
// search.php - 处理GET请求
if (isset($_GET['query']) && !empty($_GET['query'])) {
$searchQuery = trim($_GET['query']);
// 安全处理:防止XSS攻击
$searchQuery = htmlspecialchars($searchQuery, ENT_QUOTES, 'UTF-8');
echo "您搜索的内容是:" . $searchQuery;
// 这里可以执行数据库搜索操作
// $results = searchDatabase($searchQuery);
} else {
echo "请输入搜索关键词";
}
?>
URL参数构建
<?php
// 手动构建GET URL
$params = [
'category' => 'books',
'page' => 2,
'sort' => 'price'
];
$queryString = http_build_query($params);
$url = 'products.php?' . $queryString;
// 结果:products.php?category=books&page=2&sort=price
// 重定向到带参数的URL
header('Location: ' . $url);
exit;
?>
分页示例
<?php
// 分页处理示例
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$perPage = 10;
// 计算偏移量
$offset = ($page - 1) * $perPage;
// 构建分页链接
function buildPageLink($currentPage, $totalPages) {
$links = '';
// 上一页
if ($currentPage > 1) {
$links .= '<a href="?page=' . ($currentPage - 1) . '">上一页</a> ';
}
// 页码
for ($i = 1; $i <= $totalPages; $i++) {
if ($i == $currentPage) {
$links .= '<strong>' . $i . '</strong> ';
} else {
$links .= '<a href="?page=' . $i . '">' . $i . '</a> ';
}
}
// 下一页
if ($currentPage < $totalPages) {
$links .= '<a href="?page=' . ($currentPage + 1) . '">下一页</a>';
}
return $links;
}
?>
POST方法详解
基本表单处理
<!-- HTML表单使用POST方法 -->
<form action="register.php" method="post">
<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">注册</button>
</form>
<?php
// register.php - 处理POST请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 获取并清理POST数据
$username = trim($_POST['username'] ?? '');
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
// 基本验证
$errors = [];
if (empty($username)) {
$errors[] = '用户名不能为空';
} elseif (strlen($username) < 3) {
$errors[] = '用户名至少3个字符';
}
if (empty($email)) {
$errors[] = '邮箱不能为空';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = '邮箱格式不正确';
}
if (empty($password)) {
$errors[] = '密码不能为空';
} elseif (strlen($password) < 8) {
$errors[] = '密码至少8个字符';
}
// 如果没有错误,处理注册逻辑
if (empty($errors)) {
// 密码加密
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
// 保存到数据库(示例)
// saveUser($username, $email, $hashedPassword);
echo "注册成功!欢迎," . htmlspecialchars($username);
} else {
// 显示错误信息
foreach ($errors as $error) {
echo '<p style="color: red;">' . htmlspecialchars($error) . '</p>';
}
}
}
?>
文件上传处理
<!-- 文件上传表单 -->
<form action="upload.php" method="post" enctype="multipart/form-data">
<div>
<label for="file">选择文件:</label>
<input type="file" id="file" name="file" accept="image/*" required>
</div>
<div>
<label for="description">文件描述:</label>
<textarea id="description" name="description" rows="3"></textarea>
</div>
<button type="submit">上传文件</button>
</form>
<?php
// upload.php - 处理文件上传
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['file'];
// 文件信息
$fileName = $file['name'];
$fileTmpName = $file['tmp_name'];
$fileSize = $file['size'];
$fileType = $file['type'];
// 文件验证
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 5 * 1024 * 1024; // 5MB
if (!in_array($fileType, $allowedTypes)) {
die('只允许上传 JPEG、PNG 和 GIF 图片');
}
if ($fileSize > $maxSize) {
die('文件大小不能超过 5MB');
}
// 生成唯一文件名
$fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
$newFileName = uniqid() . '.' . $fileExtension;
$uploadDir = 'uploads/';
// 确保上传目录存在
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
// 移动文件到目标位置
if (move_uploaded_file($fileTmpName, $uploadDir . $newFileName)) {
$description = $_POST['description'] ?? '';
// 保存文件信息到数据库
// saveFileInfo($newFileName, $description, $fileType, $fileSize);
echo "文件上传成功!文件名:" . htmlspecialchars($newFileName);
} else {
echo "文件上传失败";
}
} else {
echo "请选择要上传的文件";
}
}
?>
GET vs POST 对比
详细对比表
| 特性 | GET | POST |
|---|---|---|
| 数据传递方式 | URL参数 | HTTP请求体 |
| 数据长度限制 | 约2048字符 | 无限制 |
| 安全性 | 较低(数据可见) | 较高(数据隐藏) |
| 缓存 | 可缓存 | 不可缓存 |
| 书签 | 可收藏 | 不可收藏 |
| 浏览器历史 | 保存 | 不保存 |
| 幂等性 | 幂等 | 非幂等 |
| 用途 | 获取数据 | 提交数据 |
选择指南
使用GET的场景:
- 搜索功能
- 分页
- 过滤和排序
- 获取资源
- 书签友好的操作
使用POST的场景:
- 用户注册/登录
- 表单提交
- 文件上传
- 敏感数据传输
- 状态改变操作
安全性考虑
1. 防止XSS攻击
<?php
// 始终对用户输入进行转义
$userInput = $_GET['input'] ?? '';
$safeOutput = htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
echo $safeOutput;
?>
2. 防止CSRF攻击
<?php
session_start();
// 生成CSRF令牌
function generateCsrfToken() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
// 验证CSRF令牌
function validateCsrfToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
// 在表单中包含令牌
$csrfToken = generateCsrfToken();
?>
<!-- 在HTML表单中添加隐藏字段 -->
<input type="hidden" name="csrf_token" value="<?php echo $csrfToken; ?>">
<?php
// 处理表单时验证令牌
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$token = $_POST['csrf_token'] ?? '';
if (!validateCsrfToken($token)) {
die('CSRF验证失败');
}
// 处理表单数据...
}
?>
3. 输入验证和过滤
<?php
// 使用PHP内置过滤器
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 120]
]);
// 自定义过滤函数
function sanitizeInput($input, $type = 'string') {
switch ($type) {
case 'email':
return filter_var($input, FILTER_SANITIZE_EMAIL);
case 'int':
return filter_var($input, FILTER_SANITIZE_NUMBER_INT);
case 'string':
default:
return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
}
}
?>
综合示例:搜索和过滤系统
HTML表单
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>产品搜索</title>
<style>
.search-form {
margin: 20px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, select {
padding: 8px;
border: 1px solid #ccc;
border-radius: 3px;
}
button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 3px;
cursor: pointer;
}
.results {
margin-top: 20px;
}
</style>
</head>
<body>
<h1>产品搜索</h1>
<!-- GET搜索表单 -->
<form method="get" class="search-form">
<div class="form-group">
<label for="keyword">关键词:</label>
<input type="text" id="keyword" name="keyword"
value="<?php echo htmlspecialchars($_GET['keyword'] ?? ''); ?>"
placeholder="输入产品关键词">
</div>
<div class="form-group">
<label for="category">分类:</label>
<select id="category" name="category">
<option value="">全部分类</option>
<option value="electronics" <?php echo (($_GET['category'] ?? '') === 'electronics') ? 'selected' : ''; ?>>
电子产品
</option>
<option value="books" <?php echo (($_GET['category'] ?? '') === 'books') ? 'selected' : ''; ?>>
图书
</option>
<option value="clothing" <?php echo (($_GET['category'] ?? '') === 'clothing') ? 'selected' : ''; ?>>
服装
</option>
</select>
</div>
<div class="form-group">
<label for="minPrice">最低价格:</label>
<input type="number" id="minPrice" name="min_price"
value="<?php echo htmlspecialchars($_GET['min_price'] ?? ''); ?>"
min="0" step="0.01">
</div>
<div class="form-group">
<label for="maxPrice">最高价格:</label>
<input type="number" id="maxPrice" name="max_price"
value="<?php echo htmlspecialchars($_GET['max_price'] ?? ''); ?>"
min="0" step="0.01">
</div>
<button type="submit">搜索</button>
<a href="?">清除筛选</a>
</form>
<!-- 搜索结果将通过AJAX加载到这个区域 -->
<div id="results" class="results">
<!-- 结果内容 -->
</div>
</body>
</html>
PHP处理逻辑
<?php
// search.php
function searchProducts($params) {
// 模拟数据库查询
$allProducts = [
['id' => 1, 'name' => '智能手机', 'category' => 'electronics', 'price' => 2999.99],
['id' => 2, 'name' => 'PHP编程指南', 'category' => 'books', 'price' => 89.90],
['id' => 3, 'name' => '运动T恤', 'category' => 'clothing', 'price' => 199.00],
['id' => 4, 'name' => '笔记本电脑', 'category' => 'electronics', 'price' => 5999.99],
['id' => 5, 'name' => 'JavaScript高级编程', 'category' => 'books', 'price' => 129.00],
];
$filteredProducts = $allProducts;
// 关键词过滤
if (!empty($params['keyword'])) {
$keyword = strtolower($params['keyword']);
$filteredProducts = array_filter($filteredProducts, function($product) use ($keyword) {
return strpos(strtolower($product['name']), $keyword) !== false;
});
}
// 分类过滤
if (!empty($params['category'])) {
$filteredProducts = array_filter($filteredProducts, function($product) use ($params) {
return $product['category'] === $params['category'];
});
}
// 价格过滤
if (!empty($params['min_price'])) {
$minPrice = (float)$params['min_price'];
$filteredProducts = array_filter($filteredProducts, function($product) use ($minPrice) {
return $product['price'] >= $minPrice;
});
}
if (!empty($params['max_price'])) {
$maxPrice = (float)$params['max_price'];
$filteredProducts = array_filter($filteredProducts, function($product) use ($maxPrice) {
return $product['price'] <= $maxPrice;
});
}
return array_values($filteredProducts);
}
// 处理搜索请求
$searchParams = [
'keyword' => trim($_GET['keyword'] ?? ''),
'category' => $_GET['category'] ?? '',
'min_price' => $_GET['min_price'] ?? '',
'max_price' => $_GET['max_price'] ?? ''
];
$results = searchProducts($searchParams);
// 显示搜索结果
if (!empty($results)) {
echo '<h3>搜索结果(共 ' . count($results) . ' 个产品)</h3>';
foreach ($results as $product) {
echo '<div class="product" style="border: 1px solid #eee; padding: 15px; margin: 10px 0; border-radius: 5px;">';
echo '<h4>' . htmlspecialchars($product['name']) . '</h4>';
echo '<p>分类:' . htmlspecialchars($product['category']) . '</p>';
echo '<p>价格:¥' . number_format($product['price'], 2) . '</p>';
echo '<form method="post" action="add_to_cart.php" style="display: inline;">';
echo '<input type="hidden" name="product_id" value="' . $product['id'] . '">';
echo '<button type="submit" name="action" value="add_to_cart">加入购物车</button>';
echo '</form>';
echo '</div>';
}
} else {
echo '<p>没有找到符合条件的产品。</p>';
}
?>
最佳实践
- 正确选择HTTP方法:根据操作性质选择GET或POST
- 输入验证:始终验证和清理用户输入
- 安全性考虑:防范XSS、CSRF等攻击
- 错误处理:提供清晰的错误信息
- 用户体验:使用适当的反馈机制
总结
GET和POST方法是PHP Web开发中最基础也是最重要的概念。正确理解和使用这两种方法,掌握它们的特点和适用场景,是开发安全、高效的Web应用程序的基础。通过本章的学习,你应该能够根据具体需求选择合适的HTTP方法,并实现安全可靠的数据处理逻辑。