在PHP中,$_GET是一个超全局变量,用于收集来自使用method="get"的表单数据,或者通过URL查询字符串传递的参数。它是Web开发中获取用户输入的重要方式之一。
$_GET是一个关联数组,包含了通过URL查询字符串传递的所有参数。当表单使用method="get"提交时,表单数据会自动添加到$_GET数组中。
| 特点 | 说明 |
|---|---|
| 数据类型 | 关联数组 |
| 数据来源 | URL查询字符串(?key=value&key2=value2) |
| 数据可见性 | 数据在URL中可见 |
| 数据长度限制 | 受URL长度限制(通常2000字符左右) |
| 缓存 | 可被浏览器缓存 |
| 安全性 | 不适合传输敏感信息 |
HTML 表单示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>GET方法表单示例</title>
</head>
<body>
<h1>用户信息表单(GET方法)</h1>
<form action="process_get.php" method="get">
<div style="margin-bottom: 15px;">
<label for="fname">名字:</label>
<input type="text" id="fname" name="fname" placeholder="请输入您的名字">
</div>
<div style="margin-bottom: 15px;">
<label for="age">年龄:</label>
<input type="number" id="age" name="age" placeholder="请输入您的年龄" min="1" max="120">
</div>
<div style="margin-bottom: 15px;">
<label for="country">国家:</label>
<select id="country" name="country">
<option value="">请选择国家</option>
<option value="china">中国</option>
<option value="usa">美国</option>
<option value="uk">英国</option>
</select>
</div>
<div style="margin-bottom: 15px;">
<label>兴趣爱好:</label><br>
<input type="checkbox" id="coding" name="hobbies[]" value="coding">
<label for="coding">编程</label>
<input type="checkbox" id="reading" name="hobbies[]" value="reading">
<label for="reading">阅读</label>
<input type="checkbox" id="sports" name="hobbies[]" value="sports">
<label for="sports">运动</label>
</div>
<input type="submit" value="提交" style="padding: 10px 20px;">
</form>
</body>
</html>
PHP 处理脚本 (process_get.php):
<?php
// 检查是否有GET参数传递
echo "<h1>接收到的GET数据</h1>";
// 方法1:直接访问特定参数(不安全,不推荐)
if (isset($_GET['fname'])) {
echo "<p><strong>名字:</strong> " . htmlspecialchars($_GET['fname']) . "</p>";
}
if (isset($_GET['age'])) {
echo "<p><strong>年龄:</strong> " . htmlspecialchars($_GET['age']) . "</p>";
}
// 方法2:遍历所有GET参数(更安全)
echo "<h2>所有GET参数:</h2>";
echo "<table border='1' cellpadding='8' style='border-collapse: collapse;'>";
echo "<tr><th>参数名</th><th>参数值</th></tr>";
foreach ($_GET as $key => $value) {
echo "<tr>";
echo "<td>" . htmlspecialchars($key) . "</td>";
// 处理数组值(如复选框)
if (is_array($value)) {
echo "<td>" . htmlspecialchars(implode(', ', $value)) . "</td>";
} else {
echo "<td>" . htmlspecialchars($value) . "</td>";
}
echo "</tr>";
}
echo "</table>";
// 显示完整的URL
echo "<h3>完整的URL:</h3>";
echo "<p>" . htmlspecialchars($_SERVER['REQUEST_URI']) . "</p>";
// 显示查询字符串
echo "<h3>查询字符串:</h3>";
echo "<p>" . htmlspecialchars($_SERVER['QUERY_STRING']) . "</p>";
?>
除了表单提交,$_GET也常用于处理URL中的查询参数。
示例:产品详情页
<?php
// product.php - 产品详情页面
// 定义产品数据(在实际应用中可能来自数据库)
$products = [
'p001' => [
'name' => 'iPhone 14',
'price' => 6999,
'category' => '手机',
'description' => '苹果最新款智能手机'
],
'p002' => [
'name' => 'MacBook Pro',
'price' => 12999,
'category' => '电脑',
'description' => '专业级笔记本电脑'
],
'p003' => [
'name' => 'AirPods Pro',
'price' => 1999,
'category' => '配件',
'description' => '降噪无线耳机'
]
];
// 检查是否有产品ID参数
if (isset($_GET['product_id']) && isset($products[$_GET['product_id']])) {
$product_id = $_GET['product_id'];
$product = $products[$product_id];
echo "<h1>产品详情</h1>";
echo "<div style='border: 1px solid #ddd; padding: 20px; border-radius: 5px;'>";
echo "<h2>" . htmlspecialchars($product['name']) . "</h2>";
echo "<p><strong>价格:</strong> ¥" . number_format($product['price'], 2) . "</p>";
echo "<p><strong>分类:</strong> " . htmlspecialchars($product['category']) . "</p>";
echo "<p><strong>描述:</strong> " . htmlspecialchars($product['description']) . "</p>";
echo "</div>";
// 显示URL以便参考
echo "<p style='margin-top: 20px; color: #666;'>";
echo "当前URL: " . htmlspecialchars($_SERVER['REQUEST_URI']);
echo "</p>";
} else {
echo "<h2>产品列表</h2>";
echo "<ul>";
foreach ($products as $id => $product) {
// 生成包含product_id参数的链接
$product_url = "product.php?product_id=" . urlencode($id);
echo "<li><a href='" . htmlspecialchars($product_url) . "'>";
echo htmlspecialchars($product['name']) . " - ¥" . number_format($product['price'], 2);
echo "</a></li>";
}
echo "</ul>";
}
?>
示例:分页和搜索功能
<?php
// search.php - 搜索和分页示例
// 模拟数据(实际应用中来自数据库)
$all_items = [
['id' => 1, 'title' => 'PHP基础教程', 'category' => '教程'],
['id' => 2, 'title' => 'MySQL数据库', 'category' => '数据库'],
['id' => 3, 'title' => 'JavaScript高级', 'category' => '前端'],
['id' => 4, 'title' => 'Python数据分析', 'category' => '数据分析'],
['id' => 5, 'title' => 'PHP实战项目', 'category' => '教程'],
['id' => 6, 'title' => 'CSS3动画', 'category' => '前端'],
['id' => 7, 'title' => 'Redis缓存', 'category' => '数据库'],
['id' => 8, 'title' => 'Vue.js框架', 'category' => '前端']
];
// 获取GET参数(带默认值)
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$keyword = isset($_GET['keyword']) ? trim($_GET['keyword']) : '';
$category = isset($_GET['category']) ? $_GET['category'] : '';
// 数据过滤
$filtered_items = $all_items;
// 关键词搜索
if (!empty($keyword)) {
$filtered_items = array_filter($filtered_items, function($item) use ($keyword) {
return stripos($item['title'], $keyword) !== false;
});
}
// 分类筛选
if (!empty($category)) {
$filtered_items = array_filter($filtered_items, function($item) use ($category) {
return $item['category'] === $category;
});
}
// 分页设置
$items_per_page = 3;
$total_items = count($filtered_items);
$total_pages = ceil($total_items / $items_per_page);
// 确保当前页有效
$page = max(1, min($page, $total_pages));
// 计算起始位置
$start = ($page - 1) * $items_per_page;
$current_items = array_slice($filtered_items, $start, $items_per_page);
// 显示搜索表单
echo "<form method='get' action='search.php' style='margin-bottom: 20px;'>";
echo "<input type='text' name='keyword' value='" . htmlspecialchars($keyword) . "' placeholder='输入关键词...'>";
echo "<select name='category'>";
echo "<option value=''>所有分类</option>";
echo "<option value='教程' " . ($category == '教程' ? 'selected' : '') . ">教程</option>";
echo "<option value='数据库' " . ($category == '数据库' ? 'selected' : '') . ">数据库</option>";
echo "<option value='前端' " . ($category == '前端' ? 'selected' : '') . ">前端</option>";
echo "<option value='数据分析' " . ($category == '数据分析' ? 'selected' : '') . ">数据分析</option>";
echo "</select>";
echo "<input type='submit' value='搜索'>";
echo "</form>";
// 显示搜索结果
echo "<h2>搜索结果(共 {$total_items} 条)</h2>";
if (empty($current_items)) {
echo "<p>没有找到相关结果。</p>";
} else {
echo "<ul>";
foreach ($current_items as $item) {
echo "<li>";
echo "<strong>" . htmlspecialchars($item['title']) . "</strong>";
echo " - <span style='color: #666;'>" . htmlspecialchars($item['category']) . "</span>";
echo "</li>";
}
echo "</ul>";
}
// 显示分页链接
if ($total_pages > 1) {
echo "<div class='pagination' style='margin-top: 20px;'>";
// 构建基础URL(保留现有参数)
$base_url = "search.php?";
$params = [];
if (!empty($keyword)) {
$params[] = "keyword=" . urlencode($keyword);
}
if (!empty($category)) {
$params[] = "category=" . urlencode($category);
}
$param_string = implode('&', $params);
// 上一页
if ($page > 1) {
$prev_url = $base_url . $param_string . "&page=" . ($page - 1);
echo "<a href='" . htmlspecialchars($prev_url) . "'>上一页</a> ";
}
// 页码
for ($i = 1; $i <= $total_pages; $i++) {
if ($i == $page) {
echo "<strong>$i</strong> ";
} else {
$page_url = $base_url . $param_string . "&page=" . $i;
echo "<a href='" . htmlspecialchars($page_url) . "'>$i</a> ";
}
}
// 下一页
if ($page < $total_pages) {
$next_url = $base_url . $param_string . "&page=" . ($page + 1);
echo "<a href='" . htmlspecialchars($next_url) . "'>下一页</a>";
}
echo "</div>";
}
?>
敏感信息的错误示例:
<?php
// ❌ 错误:使用GET传递敏感信息
// URL将显示为:login.php?username=admin&password=123456
if (isset($_GET['username']) && isset($_GET['password'])) {
$username = $_GET['username'];
$password = $_GET['password'];
// 验证登录...
}
// ✅ 正确:使用POST传递敏感信息
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = $_POST['username'];
$password = $_POST['password'];
// 验证登录...
}
?>
安全的GET参数处理:
<?php
// 安全处理GET参数的函数
function safe_get_param($key, $default = '', $filter = FILTER_SANITIZE_STRING) {
if (!isset($_GET[$key])) {
return $default;
}
// 使用filter_var进行过滤
$value = filter_var($_GET[$key], $filter);
// 额外的清理(如果需要)
$value = trim($value);
$value = stripslashes($value);
return $value;
}
// 使用示例
$product_id = safe_get_param('product_id', '', FILTER_SANITIZE_STRING);
$page = safe_get_param('page', 1, FILTER_VALIDATE_INT);
// 验证整数范围
if ($page < 1 || $page > 100) {
$page = 1;
}
// 对于搜索关键词,进行额外的HTML转义
$keyword = safe_get_param('keyword', '');
$keyword = htmlspecialchars($keyword, ENT_QUOTES, 'UTF-8');
?>
| 特性 | GET 方法 | POST 方法 |
|---|---|---|
| 数据位置 | URL查询字符串 | HTTP请求体 |
| 数据可见性 | 可见(在URL中) | 不可见 |
| 数据长度限制 | 受URL长度限制(~2000字符) | 无限制 |
| 缓存性 | 可被缓存、书签收藏 | 不可缓存 |
| 安全性 | 较低(日志、历史记录可能记录) | 较高(不在URL中暴露) |
| 数据类型 | 只支持ASCII字符 | 支持二进制数据(如文件上传) |
| 后退/刷新 | 无害(数据在URL中) | 数据会重新提交(浏览器警告) |
| 主要用途 | 获取数据、搜索、分页、过滤 | 提交数据、创建/更新资源、敏感操作 |
实际应用场景:
代码示例:RESTful API风格的GET请求
<?php
// api.php - RESTful API示例
header('Content-Type: application/json');
// 获取资源类型和ID
$resource = isset($_GET['resource']) ? $_GET['resource'] : '';
$id = isset($_GET['id']) ? $_GET['id'] : '';
// 模拟数据
$data = [
'users' => [
'u001' => ['id' => 'u001', 'name' => '张三', 'email' => 'zhangsan@example.com'],
'u002' => ['id' => 'u002', 'name' => '李四', 'email' => 'lisi@example.com'],
],
'products' => [
'p001' => ['id' => 'p001', 'name' => '产品A', 'price' => 100],
'p002' => ['id' => 'p002', 'name' => '产品B', 'price' => 200],
]
];
// 处理API请求
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
if (empty($resource)) {
// 列出所有可用资源
echo json_encode(['resources' => array_keys($data)]);
} elseif (isset($data[$resource])) {
if (empty($id)) {
// 获取资源列表
echo json_encode(array_values($data[$resource]));
} elseif (isset($data[$resource][$id])) {
// 获取特定资源
echo json_encode($data[$resource][$id]);
} else {
http_response_code(404);
echo json_encode(['error' => '资源不存在']);
}
} else {
http_response_code(404);
echo json_encode(['error' => '资源类型不存在']);
}
break;
default:
http_response_code(405);
echo json_encode(['error' => '方法不允许']);
}
?>
问题1:URL参数包含特殊字符
<?php
// 使用urlencode()处理URL参数
$search_term = "PHP & MySQL";
$encoded_term = urlencode($search_term);
// 结果: "PHP+%26+MySQL"
$url = "search.php?q=" . $encoded_term;
// 接收时使用urldecode()
if (isset($_GET['q'])) {
$search_term = urldecode($_GET['q']);
// 记得进行安全过滤
$search_term = htmlspecialchars($search_term, ENT_QUOTES, 'UTF-8');
}
?>
问题2:处理数组参数
<?php
// 表单中有 name="categories[]" 的多个复选框
// URL将显示为: process.php?categories[]=php&categories[]=mysql
if (isset($_GET['categories'])) {
// $_GET['categories'] 是一个数组
$categories = $_GET['categories'];
// 验证数组内容
if (is_array($categories)) {
$categories = array_map('htmlspecialchars', $categories);
echo "选择的分类: " . implode(', ', $categories);
}
}
?>
问题3:防止参数篡改
<?php
// 添加参数签名防止篡改
function generate_signed_url($params) {
$secret_key = 'your-secret-key';
// 排序参数
ksort($params);
// 构建查询字符串
$query_string = http_build_query($params);
// 生成签名
$signature = hash_hmac('sha256', $query_string, $secret_key);
// 添加签名到参数
$params['signature'] = $signature;
return 'process.php?' . http_build_query($params);
}
// 验证签名
function verify_signature($params) {
$secret_key = 'your-secret-key';
// 获取签名
$received_signature = $params['signature'] ?? '';
unset($params['signature']);
// 排序参数
ksort($params);
// 构建查询字符串
$query_string = http_build_query($params);
// 计算签名
$expected_signature = hash_hmac('sha256', $query_string, $secret_key);
return hash_equals($expected_signature, $received_signature);
}
?>