目录
文件管理模块-上传-过滤机制
文件管理模块-显示-过滤机制
思维导图
PHP知识点
功能:新闻列表,会员中心,资源下载,留言版,后台模块,模版引用,框架开发等
技术:输入输出,超全局变量,数据库操作,逻辑架构,包含上传&下载删除;
技术:JS&CSS混用,Cookie,Session操作,MVC架构,ThinkPHP引用等。
文件管理模块-上传-过滤机制
PHP文件上传
$_FILES:PHP中一个预定义的超全局变量,用于在上传文件时从客户端接收文件,并将其保存到服务器上。它是一个包含上传文件信息的数组,包括文件名、类型、大小、临时文件名等信息。
$_FILES["表单值"]["name"] 获取上传文件原始名称
$_FILES["表单值"]["type"] 获取上传文件MIME类型
$_FILES["表单值"]["size"] 获取上传文件字节单位大小
$_FILES["表单值"]["tmp_name"] 获取上传的临时副本文件名
$_FILES["表单值"]["error"] 获取上传时发生的错误代码
move_uploaded_file() 将上传的文件移动到指定位置的函数
过滤的类型:
1、无过滤机制
2、黑名单过滤机制
3、白名单过滤机制
4、文件类型过滤机制
AI生成前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传页面</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
padding: 20px;
}
h1 {
text-align: center;
margin-top: 50px;
}
form {
background-color: #fff;
border-radius: 10px;
padding: 20px;
margin-top: 30px;
max-width: 600px;
margin: 0 auto;
}
input[type="file"] {
margin-top: 20px;
margin-bottom: 20px;
}
button {
background-color: #4CAF50;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #3e8e41;
}
</style>
</head>
<body>
<h1>文件上传</h1>
<form action="upload.php" method="POST" enctype="multipart/form-data">
<label for="file">选择文件:</label>
<br>
<input type="file" id="file" name="f">
<br>
<button type="submit">上传文件</button>
</form>
</body>
</html>
无过滤机制
upload.php代码如下:
<?php $name=$_FILES['f']['name']; // 文件原名 $type=$_FILES['f']['type']; // 文件类型 $size=$_FILES['f']['size']; // 文件大小 $tmp_name=$_FILES['f']['tmp_name']; // 上传临时目录 $error=$_FILES['f']['error']; // 成功/失败 echo $name."<br>"; echo $type."<br>"; echo $size."<br>"; echo $tmp_name."<br>"; echo $error."<br>"; if(move_uploaded_file($tmp_name,'upload/'.$name)){ // 转移到网站目录/upload/ echo "文件上传成功!"; } ?>
../www/demo3/upload/xxx.png
黑名单过滤机制
upload.php代码如下:
<?php $name=$_FILES['f']['name']; // 文件原名 $type=$_FILES['f']['type']; // 文件类型 $size=$_FILES['f']['size']; // 文件大小 $tmp_name=$_FILES['f']['tmp_name']; // 上传临时目录 $error=$_FILES['f']['error']; // 成功/失败 // 上传文件后缀过滤 黑名单机制 $black_ext=array('php','asp','jsp','aspx'); //xxx.jpg xxx.png // explode('.', $name) 使用点号作为分隔符,将 $name 字符串拆分成一个数组。 // 拆分后的结果存储在变量 $fenge 中,每个元素代表一个分隔后的部分。 $fenge = explode('.',$name); // end($fenge) 返回数组 $fenge 的最后一个元素,即最后一部分的文件扩展名。 // 将最后一个元素赋给变量 $exts,即获取到文件的扩展名。 $exts = end($fenge); if(in_array($exts,$black_ext)){ echo '非法后缀文件'.$exts; }else{ move_uploaded_file($tmp_name,'upload/'.$name); echo '<script>alert("上传成功")</script>'; } ?>
根据环境不同有不同的绕过,如这里可尝试上传 php5
缺陷:若未考虑到各种变形后缀,则可能被绕过
白名单过滤机制
upload.php代码如下:
<?php $name=$_FILES['f']['name']; // 文件原名 $type=$_FILES['f']['type']; // 文件类型 $size=$_FILES['f']['size']; // 文件大小 $tmp_name=$_FILES['f']['tmp_name']; // 上传临时目录 $error=$_FILES['f']['error']; // 成功/失败 //上传文件后缀过滤 白名单机制 $allow_ext=array('png','jpg','gif','jpeg'); //xxx.jpg xxx.png $fenge = explode('.',$name); $exts = end($fenge); if(!in_array($exts,$allow_ext)){ echo '非法后缀文件'.$exts; }else{ move_uploaded_file($tmp_name,'upload/'.$name); echo '<script>alert("上传成功")</script>'; } ?>
MIME文件类型过滤机制
upload.php代码如下:
<?php $name=$_FILES['f']['name']; // 文件原名 $type=$_FILES['f']['type']; // 文件类型 $size=$_FILES['f']['size']; // 文件大小 $tmp_name=$_FILES['f']['tmp_name']; // 上传临时目录 $error=$_FILES['f']['error']; // 成功/失败 //MIME文件类型过滤 $allow_type=array('image/png','image/jpg','image/jpeg','image/gif'); if(!in_array($type,$allow_type)){ echo '非法后缀文件'; }else{ move_uploaded_file($tmp_name,'upload/'.$name); echo '<script>alert("上传成功")</script>'; } ?>
Content-Type: application/octet-stream 改为 Content-Type: image/png
文件管理模块-显示-过滤机制
功能:显示 上传 下载 删除 编辑 包含等
1.打开目录读取文件列表
2.递归循环读取文件列表
3.判断是文件还是文件夹
4.PHP.INI目录访问控制is_dir() 函数用于检查指定的路径是否是一个目录
opendir() 函数用于打开指定的目录,返回句柄,用来读取目录中的文件和子目录
readdir() 函数用于从打开的目录句柄中读取目录中的文件和子目录
open_basedir:PHP.INI中的设置用来控制脚本程序访问目录
示例代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文件列表</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<style type="text/css">
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
margin-bottom: 10px;
}
i {
margin-right: 10px;
}
a {
text-decoration: none;
color: #333;
}
</style>
</head>
<body>
<h1>当前目录下的文件列表</h1>
<ul>
</ul>
</body>
</html>
<?php
$dir = $_GET['path'] ?? './'; // 读取 GET 提交的参数 path=
//1.打开目录,读取文件列表 opendir
//2.循环读取文件列表 while readdir
//3.判断是文件还是文件夹 is_dir
//打开目录,读取文件列表 opendir
function filelist($dir){
if($dh = opendir($dir)){ // 打开文件夹
//循环读取文件列表 while readdir
while(($file=readdir($dh) )!== false){ // 循环读取每一个文件
//判断是文件还是文件夹 is_dir
if(is_dir($file)){
// PHP 后端先对变量进行替换,在发送前端代码
echo "<li><i class='fa fa-folder'></i> <a href='?path=$file'>" . $file . '</a></li>'; // . 拼接起来
}else{
echo '<li><i class="fa fa-file"></i> <a href="#">' . $file . '</a></li>';
}
}
}
}
filelist($dir);
// 文件删除
function del($file){
if(!is_dir($file)){
unlink($file); // unlink($file) 是一个 PHP 内置函数,用于删除指定的文件。
echo "<script>alert('删除成功')</script>";
}
}
if(isset($_GET['del'])){
del($_GET['del']);
}
// 文件下载
function down($filepath){
// basename($filepath) 是一个 PHP 内置函数,用于从文件路径中提取文件名部分。
$fileName = basename($filepath);
// 设置响应头,指定下载文件的 MIME 类型为 application/octet-stream,表示通用的二进制流。
header("Content-Type: application/octet-stream");
// 设置响应头,指定下载时的文件名,并将其设置为 $fileName。
header("Content-Disposition: attachment; filename=\"" . $fileName . "\"");
// 设置响应头,指定下载文件的大小。
header("Content-Length: " . filesize($filepath));
// 用于将指定文件的内容输出到浏览器,实现文件下载。
readfile($filepath);
}
if(isset($_GET['down'])){
down($_GET['down']);
}
?>
需要限制对文件/文件夹的访问权限
方式一:黑名单过滤
// 将filelist($dir);替换为下面的代码即可 //黑名单过滤 $black_filepath=array('../'); if(in_array($dir,$black_filepath)){ echo '<script>alert("禁止跨目录访问!")</script>'; }else{ filelist($dir); }
- 禁止了../ 即当 url 中传入?path=../ 时,会弹窗禁止跨目录访问!,但是这里可以输入改为..\, 即可绕过该黑名单。
方式二:PHP.INI目录访问控制
网站根目录设置为D:\phpStudy\PHPTutorial\WWW\blog,无法利用进行目录遍历