PHP 用户请求数据获取与文件上传
我们上篇教程提到,要获取 HTTP 请求数据,可以通过 $_GET
、$_POST
、$_REQUEST
等 PHP 内置的超全局变量,如果要获取 Cookie 和文件上传信息,可以通过额外的 $_COOKIE
和 $_FILES
。今天,学院君就来给大家演示下如何使用这些超全局变量获取请求数据。
GET 请求参数
我们知道,HTTP GET 请求是没有请求实体(表单请求数据)的,所有对于 GET 请求来说,请求数据以 URL 查询字符串(Query String)的形式提供的,所谓查询字符串,就是 URL 中 ?
之后的请求参数,例如对下面这个 URL 请求来说:
https://laravel.geekai.co/search?term=laravel
term=laravel
就是查询字符串,也就是 GET 请求参数。
我们在 http/index.php
中通过 var_dump($_GET)
打印 GET 请求数据:
<?php
echo '<pre>';
//var_dump($_SERVER);
var_dump($_GET);
在 http
目录下通过 php -S localhost:9000
启动 HTTP 服务器,然后在浏览器中访问 http://localhost:9000
:
当没有任何请求数据时,打印结果为空,如果请求 URL 中包含了查询字符串:
则对应的 $_GET
变量值是一个以参数名为键,参数值为值的关联数组。非常简单。显然,要获取某个具体参数值,通过键名获取即可:
$name = $_GET['name'];
$website = $_GET['website'];
printf("用户名: %s, 网站: %s\n", $name, $website);
要注意的是,$_SERVER
、$_GET
、$_POST
之类的超全局变量只能在 Web 模式下生效,如果通过命令行访问,因为不是 HTTP 请求,所以会报错:
POST 表单请求
看完 GET 请求,我们接着来看 POST 请求,对于 Web 页面而言,POST 请求通常就是表单请求,我们在 http
目录下新建一个 form.html
来编写这个 HTML 表单,并引入 Bootstrap CSS 框架来优化样式:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>POST 请求测试</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<style>
div.container {
margin-top: 50px;
}
form {
margin: 20px;
}
</style>
</head>
<body>
<div class="container col-4">
<h1 class="text-center">登录表单</h1>
<form method="post" action="index.php">
<div class="form-group">
<label for="inputUserName">用户名</label>
<input type="text" class="form-control" id="inputUserName" name="name">
</div>
<div class="form-group">
<label for="inputPassword">密码</label>
<input type="password" class="form-control" id="inputPassword" name="password">
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
</div>
</body>
</html>
我们在 form
标签中设置 method
属性值为 post
,action
属性值为 index.php
,即表示点击登录按钮后,表单数据会以 POST 方式提交到 index.php
这个脚本进行处理。
在浏览器中访问 http://localhost:9000/form.html
,就可以看到登录表单了:
修改 index.php
代码如下:
<?php
echo '<pre>';
//var_dump($_SERVER);
//var_dump($_GET);
var_dump($_POST);
$name = $_POST['name'];
$password = $_POST['password'];
printf("用户名: %s, 密码: %s\n", $name, $password);
现在,我们改为通过 $_POST
获取请求数据,使用方式和 $_GET
一样,只不过它接收的是 POST 请求数据。我们切换到登录表单页面,输入数据,点击「登录」提交表单,页面就会跳转到 index.php
,并打印出提交数据:
通过 $_REQUEST
获取请求数据
$_POST
超全局变量是无法获取 GET 请求数据的,同理,$_GET
超全局变量也无法获取 POST 请求数据,比如我们尝试在表单提交 action
对应 URL 中添加查询字符串:
<form method="post" action="index.php?website=https://laravel.geekai.co">
刷新表单页面,重写填写数据提交表单,可以看到打印 $_POST
结果中不包含 website
信息:
要同时获取 GET 和 POST 请求数据,可以通过 $_REQUEST
超全局变量,我们将 index.php
中的代码调整如下:
var_dump($_REQUEST);
$name = $_REQUEST['name'];
$password = $_REQUEST['password'];
$website = $_REQUEST['website'];
printf("用户名: %s, 密码: %s, 网站: %s\n", $name, $password, $website);
使用方式所有超全局变量都是一样的,只是现在通过 $_REQUEST
既可以获取 POST 请求数据,又可以获取 GET 请求数据,在表单提交页面重新提交表单,打印结果如下:
文件上传
表单数据除了可以包含普通的文本信息和密码信息外,还可以包含文件信息,不过对于通过表单上传的文件,不能通过之前的 $_GET
、$_POST
、$_REQUEST
超全局变量获取,只能通过专门的 $_FILES
超全局变量获取。
文件上传表单
下面我们来简单演示下如何在 PHP 中通过表单上传文件,首先在 http
子目录下新建 file.html
来编写对应的 HTML 表单:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form method="post" action="file.php" enctype="multipart/form-data">
<input type="file" name="image">
<input type="submit" value="上传">
</form>
</body>
</html>
需要注意的是文件上传只能通过 POST 请求完成,并且需要额外设置表单属性 enctype
值为 multipart/form-data
(默认是 application/x-www-form-urlencoded
)。
$_FILES
数据结构
我们在 http
目录下新建一个 PHP 脚本 file.php
来定义服务端逻辑:
<?php
echo '<pre>';
var_dump($_FILES);
首先打印 $_FILES
查看其数据结构,我们在文件上传表单中选择一个本地图片上传,上传成功后,服务端打印结果如下:
可以看到 $_FILES
是一个键值对关联数组,键名是文件上传组件设置的 name
属性,对应的值也是一个关联数组,其中包含了详细的文件信息,包含文件名、MIME 类型、文件默认上传位置(位于临时目录下)、错误信息以及文件尺寸,我们可以结合这些新息将上传文件保存到指定位置。在 PHP 中,可以通过内置函数 move_uploaded_file 将上传文件从临时目录移动到指定目录。
文件上传处理
下面我们在 file.php
中编写对应的文件上传处理代码:
<?php
//echo '<pre>';
//var_dump($_FILES);
// 获取上传文件
$image = $_FILES['image'];
// 处理文件上传过程中的错误
if ($image['error'] != UPLOAD_ERR_OK) {
switch ($image['error']) {
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
trigger_error('上传文件过大', E_USER_ERROR);
break;
case UPLOAD_ERR_PARTIAL:
trigger_error('上传文件不完整', E_USER_ERROR);
break;
case UPLOAD_ERR_NO_FILE:
trigger_error('没有文件被上传', E_USER_ERROR);
break;
case UPLOAD_ERR_NO_TMP_DIR:
trigger_error('未指定或找不到临时目录', E_USER_ERROR);
break;
case UPLOAD_ERR_CANT_WRITE:
trigger_error('上传目录无法写入', E_USER_ERROR);
break;
default:
trigger_error('其他文件上传错误', E_USER_ERROR);
break;
}
}
// 限定上传文件类型
if (!in_array($image['type'], ['image/jpeg', 'image/png', 'image/gif'])) {
trigger_error('只支持 jpg/jpeg、png、gif 格式图片上传', E_USER_WARNING);
}
// 限定上传文件大小
if ($image['size'] > 1 * 1024 * 1024) {
trigger_error('上传文件不能超过 1M', E_USER_WARNING);
}
// 设置文件上传路径为 Web 根目录下的 images 子目录
$uploaddir = __DIR__ . '/images/';
$filepath = $uploaddir . $image['name'];
// 移动上传文件到指定位置
if (move_uploaded_file($image['tmp_name'], $filepath)) {
// 上传成功,则在页面预览上传的图片
echo '<font color="green">文件上传成功</font><hr>';
$webpath = '/images/' . $image['name'];
echo '<img src="' . $webpath . '">';
} else {
echo '<font color="red">文件上传失败,请重试!</font>';
}
测试文件上传
最后,我们访问文件上传页面,选择一张本地图片上传,选择之后,点击「上传」按钮开始上传,上传成功后,会在 file.php
页面显示出上传的图片,表明上传成功:
好了关于文件上传,我们就简单介绍到这里,更多细节,请阅读 PHP 官方文档。
5 Comments
上传文件是 需要现在目录下创建下images目录,或者用代码判断生成
学院君大大,传统的表单提交和前后端分离使用的formdata有啥区别啊?表单能做的,formData都能做吗?
本质都是一样的啊 都是基于 HTTP 协议提交数据而已 无非是前后端分离后前端通过 JS 代码/组件表单提交的过程脚本化了
给后来码友说下,images目录要在你当前运行代码的http目录下创建。你如果不想创建,也可以通过判断这个images目录存在与否来创建。我上传后图片没有成功显示,我把路径前的/杠去掉就可以了:
$webpath='images/'.$image['name'];
composer require china-lishuo/oss-utils