javascript前端xhr利用FormData()和FileReader()函数上传图片,及后端php接收处理FormData()上传数据只能收到1个数据的处理办法和防止上传漏洞办法
//前端 的检查类型为简单检查,因为渗透会停掉前端的javascript代码,所以在后端进行检测和替换才是重点
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="UTF-8"></html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8;"/>
<title>做上传文件测试用</title>
<script type="text/javascript" src="common.js"></script>
<style type="text/css">
.button
{
margin-right: 20px;
}
#preview
{
display: flex;
flex-wrap: wrap;
width: 800px;
padding: 10px;
justify-content: start;
}
.icon-po
{
overflow: hidden;
position: relative;
width: 300px;
height: 300px;
margin-right: 20px;
margin-top: 20px;
}
.icon-close
{
position: absolute;
right: 5%;
top: 5%;
width: 30px;
border-radius: 50%;
background-color: red;
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.pic
{
width:300px;
height:300px;
}
</style>
</head>
<body>
选择文件(可多选):<input type="file" id="f1" multiple/>
<button type="button" class="button" id="btn-submit">预览图片</button>
<button type="button" id="complate">上传图片</button>
<div id="preview"></div>
<br/>
<script type="text/javascript">
var fL=[];
//创建获取图片以及预览图片
function previewUpdate(upfiles)
{
var e=0;
var preview=document.getElementById("preview");
if(upfiles.length>0)
{
for(var i=0,len=upfiles.length;i<len;i++)
{
//简单检测是否为图片类型
if(!/image\/(jpe?g|png|gif)/i.test(upfiles[i].type))
{
alert(upfiles[i].name+'不是图片');
}else
{
//上传图片不能大于1M
if(upfiles[i].size<1024*1000)
{
//最后都压入fL数组内以供后面程序调用
fL.push(upfiles[i]);
}else
{
alert('图片过大,请上传小于1M的图片');
}
}
/*这里直接输入是为了后端测试用,可以删除掉
//直接给到数组
fL.push(upfiles[i]);
*/
}
//循遍数组里面的图片对象
fL.forEach(function(item,index,array){
//创建FileReader()读取图片对象
var reader=new FileReader();
//为预览图片创建容器和关闭按钮,div1为装图片的容器,div2为关闭单个div1容器
var div1=document.createElement("div");
var div2=document.createElement("div");
div1.className="icon-po";
div2.className="icon-close";
div2.innerHTML='X';
//为每个容器和关闭按钮设置显示前后顺序
div1.index=div2.index=e;
e++;
//reader.onload为读取完成后创建图片对象,添加到div1容器中
reader.onload=function(event){
var img=new Image();
img.className="pic";
//获得图片的URL连接,方便预览
img.src=reader.result;
img.title=item.name;
div1.appendChild(img);
div1.appendChild(div2);
preview.appendChild(div1);
//点击关闭按钮div2,删除div1子节
div2.onclick=function(){
console.log(item);
div1.remove();
//同时删除div1容器图片对象在fL数组中相应的值
fL.splice(index,1);
//console.log(fL);
}
};
//读取数组中的每一项图片对象
reader.readAsDataURL(item);
});
}else
{
console.log('请选择文件 ');
}
}
//上传图片函数
function complateUpdate()
{
//创建xhr对象
var xhr=new createXHR();
//判断数组是否不为空
if(fL.length>0)
{
//创建formdata()
var fd=new FormData();
//注意:这里必须用for in来将fL中的图片对象添加到fd当中,相当于是循环取出对象
//不能用for(var i=0,len=fL.length;i<len;i++)循环
//或是fl.forEach()这些,用这些方法传过去的图片,后端都是只能接收到最后一个
for(var files in fL)
{
//files表示的是fL中的键,一般就是数字的自然数,fL[files]就是数组中的图片对象了
fd.append(files,fL[files]);
xhr.open("post","ajax.php",true);
xhr.send(fd);
}
//xhr.onload加载完成时触发的事件是回调 后端传来的数据
xhr.onload=function(){
if((xhr.status>=200 && xhr.status<300)|| xhr.status==304)
{
alert(xhr.responseText);
}else
{
console.log("接收数据发生错误");
}
};
}else
{
alert('无图片');
}
}
var button=document.getElementById('btn-submit');
var upfiles=document.getElementById("f1");
var upbutton=document.getElementById("complate");
//选择上传图片后就显示预览
upfiles.onchange=function(){
previewUpdate(upfiles.files);
}
//点击预览按钮可变换显示和隐藏预览图片
button.onclick=function(){
var preview=document.getElementById("preview");
var allStyle=document.defaultView.getComputedStyle(preview,null);
if(allStyle.display!="none"){
preview.style.display="none";
}else
{
preview.style.display="flex";
}
};
//上传按钮提交上传的图片
upbutton.onclick=function(){
complateUpdate();
//数组清空,防止重复提交
fL=[];
var preview=document.getElementById("preview");
//清空预览区已经上传的图片
preview.innerHTML='';
};
</script>
</body>
</html>
//后端文件,就是在 xhr.open(“post”,“ajax.php”,true);这句里面的ajax.php
<?php
header('Content-type:text/plain;enctype:multipart/form-data');
if($files=$_FILES)
{
//设置路径
$path="images/";
if(!file_exists($path))
{
mkdir("$path",0700);
}
//将多张图片循环出来
for($i=0;$i<count($files);$i++)
{
//获取文件名后缀
$pos[$i]=trim(strrchr($files[$i]['name'],"."),".");
//获取文件类型
$type[$i]=$files[$i]['type'];
//获取文件临时名字
$tmp_name[$i]=$files[$i]['tmp_name'];
//创建一个完整的随机名字的新图片文件
$newfile[$i]=$path.strval(rand()).".$pos[$i]";
//用getimagesize()获取每个图片的类型,必须是临时文件的类型,如果是用$files[$i]['name']来获取类型会出错
//getimagesize()说有漏洞问题,最好用@隐藏下出错的错误显示,
//为什么这里又要获取图片的类型?因为$files[$i]['type']获取到图片的类型并不准确
$typemime[$i]=@getimagesize($files[$i]['tmp_name']);
//array_diff比较两个数组值的差集,就是比较参数1的值,是不是在参数2中都有,如果有一项不是,则会输出这个值,这函数也可以比较对象
$result=array_diff($pos,array('png','jpeg','jpg','gif'));
$rtype=array_diff($type,array('image/jpeg','image/png','image/jpg','image/gif'));
if(count($result)===0 && count($rtype)===0)
{
//图片是否小于1M
if($files[$i]['size']<1024*1000){
//将临时文件移动到新创建的图片中
if(move_uploaded_file($tmp_name[$i],$newfile[$i]))
{
//这里就用了getimagesize()获取到的类型['mime']来选择用那块创建新的图片
//用imagecreatefromjpreg/png/gif可以有效清除图片中的恶意代码,也可以判断是不是图片
//如果不是图片是创建不了新图片的,目前这是最有效的防恶意代码的方法,其它办法:如去写清理图片中的代码总有漏洞
switch($typemime[$i]['mime'])
{
case 'image/jpeg':
$im=imagecreatefromjpeg($newfile[$i]);
break;
case 'image/png':
$im=imagecreatefrompng($newfile[$i]);
break;
case 'image/gif':
$im=imagecreatefromgif($newfile[$i]);
break;
case 'image/jpg':
$im=imagecreatefromjpeg($newfile[$i]);
break;
default:
$im=false;
break;
}
if($im==false)
{
echo "只支持png,jpeg,gif,jpg图片格式,请勿上传其它类型文件";
@unlink($newfile[$i]);
}
else
{
//再重新创建一个新的空白图片
$img_path[$i]=$path.date('YmdHis').strval(rand()).".$pos[$i]";
//将上面创建的$im图像对象句柄写入新的空白图片中
imagejpeg($im,$img_path[$i]);
@unlink($newfile[$i]);
//清理句柄释放内存
imagedestroy($im);
echo $files[$i]['name'].'上传成功';
}
}else
{
echo '上传出错,确保图片格式正确';
}
}else
{
echo '图片过大,必须小于1M';
}
}else
{
echo '上传失败!文件类型不正确,请确保正确的图片格式。';
}
}
}else
{
echo '未获取到数据';
}
?>
上一篇: JavaScript
下一篇: 【JavaScrip