PHP教程系列二-----文件上传(1)

文件结构

使用前后端分离的形式,一个前端页面文件,一个php文件,用于接收文件,一个目录用于存放文件。

前端页面

先放代码,如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>图片上传</title>
		<script>
			//实现预览功能
			function preview() {
				//获取文件框的第一个文件,因为文件有可能上传多个文件,咱这里是一个文件
				var file = document.getElementById("fileload").files[0];
				//可以进行一下文件类型的判断
				var fileType = file.type.split("/")[0];
				if(fileType != "image") {
					alert("请上传图片")
					return;
				}
				//图片大小的限制
				var fileSize = Math.round(file.size / 1024 / 1024);
				if(fileSize >= 2) {
					alert("请上传小于少于2M的图片");
					return;
				}
				//获取img对象
				var img = document.getElementById("image");
				//建一条文件流来读取图片
				var reader = new FileReader();
				//根据url将文件添加的流中
				reader.readAsDataURL(file);
				//实现onload接口
				reader.onload = function(e) {
					//获取文件在流中url
					url = reader.result;
					//将url赋值给img的src属性
					img.src = url;
				};
			}
			//实现取消上传功能
			function call() {
				//将img的src属性赋值为空串
				document.getElementById("image").src = "";
				//选择文件框的value属性赋值为空串
				document.getElementById("fileload").value = "";
			}
			function upload(){
				var formData = new FormData(); 
				formData.append("upfile", document.getElementById('fileload').files[0]); 
				var xhr = new XMLHttpRequest();
				xhr.open('POST', '/study/recv_file.php');
				// 上传完成后的回调函数
				xhr.onload = function () {
				  if (xhr.status === 200) {
				  console.log('上传成功');
				  } else {
				   console.log('上传出错');
				  }
				};
				// 获取上传进度
				xhr.upload.onprogress = function (event) {
				  if (event.lengthComputable) {
					var percent = Math.floor(event.loaded / event.total * 100) ;
					// 设置进度显示
					document.getElementById("J_upload_progress").value = percent;
					document.getElementById("J_upload_progress").innerText = percent + "%";
				  }
				};
				xhr.send(formData);

			}
		</script>
	</head>
	<body>
		<input id="fileload" type="file" onchange="preview();" />
		<input id="upload_btn" type="button" value="upload" onclick="upload();"/>
		<!--建一个文件选择框-->
		<input type="button" value="取消" onclick="call();" />
		<progress id="J_upload_progress" value="0" max="100"></progress>
		<h2>预览</h2>
		<div style="width: 400px;height: 400px;border: 1px solid #303030;">
			<!--设置一个框放图片-->
			<img id="image" width="100%" height="100%" src="" />
			<!--放图片的标签-->
		</div>
	</body>
</html>

页面设计比较简单,以实现功能为主要目的。效果如下图:
在这里插入图片描述页面功能比较简单,使用的设计方法也很传统,就不做过多介绍了

后端代码

<?php
function file_type($filename)  
{  
    $file = fopen($filename, "rb");  
    $bin = fread($file, 2); //只读2字节  
    fclose($file);  
    $strInfo = @unpack("C2chars", $bin);  
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);  
    $fileType = '';  
    switch ($typeCode)  
    {  
        case 7790:  
            $fileType = 'exe';  
            break;  
        case 7784:  
            $fileType = 'midi';  
            break;  
        case 8297:  
            $fileType = 'rar';  
            break;          
        case 8075:  
            $fileType = 'zip';  
            break;  
        case 255216:  
            $fileType = 'jpg';  
            break;  
        case 7173:  
            $fileType = 'gif';  
            break;  
        case 6677:  
            $fileType = 'bmp';  
            break;  
        case 13780:  
            $fileType = 'png';  
            break;  
        default:  
            $fileType = 'unknown: '.$typeCode;  
    }  
  
    //Fix  
    if ($strInfo['chars1']=='-1' AND $strInfo['chars2']=='-40' ) return 'jpg';  
    if ($strInfo['chars1']=='-119' AND $strInfo['chars2']=='80' ) return 'png';  
  
    return $fileType;  
}  
try {
   
    // Undefined | Multiple Files | $_FILES Corruption Attack
    // If this request falls under any of them, treat it invalid.
    if (
        !isset($_FILES['upfile']['error']) ||
        is_array($_FILES['upfile']['error'])
    ) {
		var_dump($_FILES);
        throw new RuntimeException('Invalid parameters.');
    }

    // Check $_FILES['upfile']['error'] value.
    switch ($_FILES['upfile']['error']) {
        case UPLOAD_ERR_OK:
            break;
        case UPLOAD_ERR_NO_FILE:
            throw new RuntimeException('No file sent.');
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            throw new RuntimeException('Exceeded filesize limit.');
        default:
            throw new RuntimeException('Unknown errors.');
    }

    // You should also check filesize here.
    if ($_FILES['upfile']['size'] > 2*1024*1024) {
        throw new RuntimeException('Exceeded filesize limit.');
    }

    // DO NOT TRUST $_FILES['upfile']['mime'] VALUE !!
    // Check MIME Type by yourself.
	$ext = file_type($_FILES['upfile']['tmp_name']);
    if ($ext != 'jpg' && $ext != 'bmp' && $ext != 'png' && $ext != 'gif') {
        throw new RuntimeException('Invalid file format.');
    }

    // You should name it uniquely.
    // DO NOT USE $_FILES['upfile']['name'] WITHOUT ANY VALIDATION !!
    // On this example, obtain safe unique name from its binary data.
    if (!move_uploaded_file(
        $_FILES['upfile']['tmp_name'],
        sprintf('./uploads/%s.%s',
            sha1_file($_FILES['upfile']['tmp_name']),
            $ext
        )
    )) {
        throw new RuntimeException('Failed to move uploaded file.');
    }

    echo 'File is uploaded successfully.';

} catch (RuntimeException $e) {
    echo $e->getMessage();
}
?>

其中file_type是从网络查找的一个判断文件类型的算法,因为使用$_FILES变量中的文件类型做判断并不是十分准确,客户端可以造假,file_type这个函数也不是很准备,但对于一般的应用足够了。move_uploaded_file用于把文件从临时目录移动我们的上传目录

结语

今天就写这些吧,下一篇使用三方库(js)来优化代码。
[1]: https://segmentfault.com/a/1190000008791342
[2]: https://blog.csdn.net/lkwan123/article/details/72830955

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值