本文目录
一、表单的参数传递
1.1 复选框参数传递
复选框参数传递存在问题,例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (isset($_POST['button'])) {
echo $_POST['languages'];
}
?>
<form action="" method="post">
语言:<input type="checkbox" name="languages" value="PHP">PHP
<input type="checkbox" name="languages" value="javascript">javascript
<input type="checkbox" name="languages" value="node">node
<input type="checkbox" name="languages" value="vue">vue
<button type="submit" name="button">确定</button>
</form>
</body>
</html>
效果:
可以很直观的发现,复选框当我们选择两个以上时只会选择最后一个,那么我们需要在复选框的name属性后加个[ ]
表示这个是一系列的数组,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (isset($_POST['button'])) {
print_r($_POST['languages']);
}
?>
<form action="" method="post">
语言:<input type="checkbox" name="languages[]" value="PHP">PHP
<input type="checkbox" name="languages[]" value="javascript">javascript
<input type="checkbox" name="languages[]" value="node">node
<input type="checkbox" name="languages[]" value="vue">vue
<button type="submit" name="button">确定</button>
</form>
</body>
</html>
效果:
这样就可以解决复选框的问题了。
1.2 其他表单参数传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (isset($_POST['button'])) {
echo '姓名:'.$_POST['username'].'<br/>';
echo '密码:'.$_POST['password'].'<br/>';
echo '性别:'.$_POST['sex'].'<br/>';
echo '居住地:'.$_POST['area'].'<br/>';
echo '留言:'.$_POST['mark'].'<br/>';
}
echo '<hr/>';
?>
<form action="" method="post">
姓名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
性别:<input type="radio" name="sex" value="1" checked>男
<input type="radio" name="sex" value="0">女<br/>
爱好:
居住地:
<select name="area">
<option value="amoy">厦门</option>
<option value="fuzhou">福州</option>
</select><br/>
备注:<textarea name="mark" cols="30" rows="5"></textarea>
<button type="submit" name="button">确定</button>
</form>
</body>
</html>
效果:
二、文件参数的传递(二进制)
2.1 文件域
开发中需要上传图片、音乐、视频等等,这种上传传递是二进制数据。
文件域:<input type="file" name="image">
2.2 表单enctyoe属性
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码。
表单的enctype属性,默认情况下,表单传递的是字符流,不能传递二进制,通过enctype属性设置可以传递复合数据。
enctype有三种格式:
application/x-www-form-urlencoded
只能传字符串,带格式的,xml
multipart/form-data
能传字符串或者二进制数据,文件上传必须设置这个。text/plain
传字符串,不带格式。
2.3 接收文件$_FILES
超全局变量$_FILES
是一个二维数组,用来保存客户端上传到服务器的文件信息。二维数组的行是文件域的名称,列有5个。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
echo '<pre/>';
print_r($_FILES);
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="image">
<button type="submit" name="button">上传</button>
</form>
</body>
</html>
效果:
- name:上传的文件名
- type:上传的类型,这个类型是MIME类型
- size:文件的大小,以字节为单位
- tmp_name:文件上传时的临时文件
- error:错误的编码(值有0、1、2、3、4、6、7)0表示正确
error值描述:
error值 | 错误描述 |
---|---|
0 | 正确 |
1 | 文件大小超过了php.ini允许的最大值 |
2 | 文件大小超过了表单允许的最大值 |
3 | 只有部分文件上传 |
4 | 没有文件上传 |
6 | 找不到临时文件 |
7 | 文件写入失效 |
可以在php.ini中设置允许的最大值:
php.ini中设置允许最大为2M。
设置表单允许的最大值:
只要掌握错误号,0和4即可。
2.4 将上传文件移到指定位置。move_uploaded_file(临时地址, 目标地址)
函数:move_uploaded_file(临时地址, 目标地址)
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
// 如果有文件上传并且正确,进行上传文件移到指定位置
if ($_FILES['image']['error'] == 0) {
move_uploaded_file($_FILES['image']['tmp_name'], './'.$_FILES['image']['name']);
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="image">
<button type="submit" name="button">上传</button>
</form>
</body>
</html>
效果:
可以看到已经从桌面上传到www
文件夹下了。
php.ini中与上传文件相关的一些配置:
- post_max_size = 8M(表单允许的最大值)
- upload_max_filesize = 2M(允许上传文件的大小)
- upload_tmp_dir =“F:/Program/tmp”(指定临时文件地址)
- file_uploads = On(是否允许文件上传)
- max_file_uploads = 20(允许同时上传20个文件)
2.5 优化文件上传,同名处理。
在文件上传时,如果是相同名字的将覆盖,那这个肯定不是我们想要的,接下来来优化下这个问题。
在这之前,先介绍两个处理字符串的函数strchr( )
和strrchr( )
。例:
<?php
$path='counter.name.jpg';
echo strchr($path, '.');
?>
效果:
strchr( 匹配的字符串,以什么为选择起始标志) :这个方法从左边开始匹配。
<?php
$path='counter.name.jpg';
echo strrchr($path, '.');
?>
效果:
strrchr( 匹配的字符串,以什么为选择起始标志) :这个方法从右边开始匹配。
- 通过时间戳拼接3位随机数做文件名
<?php
$path='counter.name.jpg';
echo time().rand(100,999).strrchr($path, '.');
?>
效果:
2. 通过php自带的uniqid( )做文件名
uniqid(前缀,true)。
例:
<?php
$path='counter.name.jpg';
echo uniqid('goods_').strrchr($path, '.'), '<br/>';
echo uniqid('goods_', true).strrchr($path, '.');
?>
效果:
2.6 验证文件格式
- 判断文件后缀名。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
$arr=array('.jpg','.png','.gif'); // 允许的扩展名
$ext=strrchr($_FILES['languages']['name'],'.'); // 上传文件扩展名
if (in_array($ext, $arr)) {
echo '允许上传';
}
else {
echo '不允许上传';
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上传</button>
</form>
</body>
</html>
效果:
但是如果我在桌面新建一个记事本,aa.txt
,然后我将后缀改为.jpg
,那么它也是允许上传的,但是他的本质还是文本,所以这里的安全系数不高。不能防止文件伪装。
- 判断mime类型
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
$arr=array('image/jpeg','image/png','image/gif'); // 允许的扩展名
$mime=$_FILES['languages']['type']; // mime类型
if (in_array($mime, $arr)) {
echo '允许上传';
}
else {
echo '不允许上传';
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上传</button>
</form>
</body>
</html>
效果:
可以看到判断mime类型也不能防止文件伪装。
- php_fileinfo扩展
在php.ini配置中找到如图:
开启扩展后,就可以调用里面定义的函数。例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
// 1.创建finfo资源
$info=finfo_open(FILEINFO_MIME_TYPE);
var_dump($info);
// 2.将finfo资源和文件做比较
echo finfo_file($info,$_FILES['languages']['tmp_name']);
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上传</button>
</form>
</body>
</html>
效果:
那么这个就可以防止文件伪装了,它可以强大到你的记事本是空的都知道,如果写了内容或者脚本也能分析出来,这边就不试了,就是在aa.jpg
中写入js
脚本,它也能检测出来。感兴趣的小伙伴可以自己试试。
三、优化文件上传例题
- 验证是否有误
- 验证格式
- 验证大小
- 验证是否是http上传
- 上传实现
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
function checkErr($file) {
$error = $file['error'];
// 1.验证错误
if ($error != 0) {
switch ($error) {
case 1:
return '文件大小超过了php.ini允许的最大值'.ini_get('upload_max_filesize');
case 2:
return '文件大小超过了表单允许的最大值';
case 3:
return '只有部分文件上传';
case 4:
return '没有文件上传';
case 6:
return '找不到临时文件';
case 7:
return '文件写入失效';
default:
return '未知错误';
}
}
// 2.验证格式
$info=finfo_open(FILEINFO_MIME_TYPE);
$mime=finfo_file($info,$file['tmp_name']);
$arr=array('image/jpeg','image/png','image/gif');
if (!in_array($mime,$arr)) {
return '只能上传'.implode(',',$arr);
}
// 3.验证大小
$size=1024000;
if ($file['size']>$size) {
return '文件大小不能超过'.number_format($size/1024,1).'kb';
}
// 4.验证是否是http上传
if (!is_uploaded_file($file['tmp_name'])) {
return '文件不是HTTP POST 上传的<br/>';
}
return null;
}
if (!empty($_POST)) {
if ($err = checkErr($_FILES['languages'])) {
echo $err;
}
else {
// 5.文件上传
//$folder=date('Y-m-d H:i:s') // 将当前的时间转成 年-月-日 小时:分钟:秒数
echo $folder=date('Y-m-d'); // 文件夹名称
$path="./uploads/${folder}"; // 文件夹路径
if (!is_dir($path)) {
mkdir($path);
}
else {
$filename=uniqid('',true).strrchr($_FILES['languages']['name'], '.'); // 文件名
$filepath="$path/$filename"; // 文件路径
if (move_uploaded_file($_FILES['languages']['tmp_name'], $filepath)) {
echo "上传成功,路径是:${filepath}";
}
else {
echo '失败<br/>';
}
}
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上传</button>
</form>
</body>
</html>
效果:
可以看到按照预期的上传成功了。
在学习的php的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。