文件上传与下载
文件上传
- 文件上传表单
- 表单的提交方式必须为POST
enctype="multipart/form-data"
- 说明浏览器可以提供文件上传功能
- 该属性提示表单中有二进制文件数据
<input type="hidden" name="max_file_size" value="30000">
- 可以指定允许上传文件的最大尺寸
- MAX_FILE_SIZE必须在文件域的上面。
<!-- form.html -->
<form action="upload.php" enctype="multipart/form-data" method="post">
<input type="hidden" name="max_file_size" value="30000">
选择文件:<input type="file" name="userfile">
<input type="submit" value="上传文件">
</form>
-
文件域 表单的enctype属性
- 默认情况下,表单传递是字符流,不能传递二进制流
- 通过设置表单的enctype属性传递复合数据
- enctype属性的值有
application/x-www-form-urlencoded
(默认)表示传递的是带格式的文本数据multipart/form-data
复合的表单数据(字符串文件),文件上传必须设置此值text/plain
用于向服务器传递无格式的文本数据,主要用户电子邮件
-
PHP处理上传文件
- PHP会自动生成一个$_FILES二维数组,该数组保存了上传文件的信息
# upload.php
<?php
$name= $_FILES['userfile']['name'];
$type= $_FILES['userfile']['type'];
$size= $_FILES['userfile']['size'];
$tmpName= $_FILES['userfile']['tmp_name'];
$error= $_FILES['userfile']['error'];
echo "{$name}<br>{$type}<br>{$size}<br>{$tmpName}<br>{$error}";
?>
-
$_FILES['userfile']
键值说明$_FILES['userfile']['name']
上传文件的名称$_FILES['userfile']['type']
上传文件的MIME类型(image/jpeg、image/gif、image/png)$_FILES['userfile']['size']
上传文件的大小,以字节为单位$_FILES['userfile']['tmp_name']
文件上传时的临时文件$_FILES[][‘error’]
错误编码(值有0、1、2、3、4、6、7)- 0 - 正确
- 4 - 没有文件上传
- 1 - 文件大小超过了php.ini中允许的最大值 upload_max_filesize = 2M
- 2 - 文件大小超过了表单允许的最大值
- 3 - 只有部分文件上传
- 6 - 找不到临时文件
- 7 - 文件写入失败
-
与文件上传有关的配置
post_max_size = 8M
表单允许的最大值upload_max_filesize = 2M
允许上传的文件大小upload_tmp_dir =F:wamp mp
指定临时文件地址,如果不知道操作系统指定file_uploads = On
是否允许文件上传max_file_uploads = 20
允许同时上传20个文件
<?php
echo ini_get('post_max_size');
echo ini_get('upload_max_filesize');
echo ini_get('upload_tmp_dir');
echo ini_get('file_uploads');
echo ini_get('max_file_uploads');
?>
- 将上传文件移动到指定位置
move_uploaded_file()
临时地址,目标地址- 上传的同名的文件要给覆盖
# upload.php
<?php
mkdir('D:Program Filesxampphtdocsuploads');
$newDir= "uploads/".$_FILES['userfile']['name'];
if(!empty($_POST)) {
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
echo '上传有误';
echo '错误码:'.$_FILES['userfile']['error'];
exit;
}
}
?>
优化文件上传
- 更改文件名
- 通过时间戳做文件名
- 通过uniqid()实现
uniqid()
生成唯一的IDuniqid('goods_')
带有前缀uniqid('goods_',true)
唯一ID+随机数
# upload.php
<?php
# 判断是否存在目录
$dir= 'D:Program Filesxampphtdocsuploads';
if(!is_dir($dir)){
mkdir($dir);
}
# 通过时间戳做文件名
$newName= time().rand(100,999).strrchr($_FILES['userfile']['name'],'.');
$newDir= "uploads/".$newName;
# 上传服务处理
if(!empty($_POST)) {
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
echo '上传有误';
echo '错误码:'.$_FILES['userfile']['error'];
exit;
}
}
?>
# upload.php
<?php
# 判断是否存在目录
$dir= 'D:Program Filesxampphtdocsuploads';
if(!is_dir($dir)){
mkdir($dir);
}
# 通过uniqid()实现
$newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.');
$newDir= "uploads/".$newName;
# 上传服务处理
if(!empty($_POST)) {
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
echo '上传有误';
echo '错误码:'.$_FILES['userfile']['error'];
exit;
}
}
?>
- 验证文件格式
- 将文件的后缀和允许的后缀对比 (不能识别文件伪装)
- 通过
$_FIELS[]['type']
类型判断 (不能识别文件伪装) - 在php.ini中开启fileinfo扩展 (可以防止文件伪装)
# # upload.php
<?php
if(!empty($_POST)) {
# 判断是否存在目录
$dir= 'D:Program Filesxampphtdocsuploads';
if(!is_dir($dir)){
mkdir($dir);
}
# 通过uniqid()实现重命名
$newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.');
$newDir= "uploads/".$newName;
# 文件名拓展名验证
$allow= array('.jpg','.png','.gif');
$ext= strrchr($_FILES['userfile']['name'],'.');
if(!in_array($ext,$allow)){
echo '文件上传不合法';
exit;
}
# 上传服务处理
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
echo '上传有误';
echo '错误码:'.$_FILES['userfile']['error'];
exit;
}
}
?>
# upload.php
<?php
if(!empty($_POST)) {
# 判断是否存在目录
$dir= 'D:Program Filesxampphtdocsuploads';
if(!is_dir($dir)){
mkdir($dir);
}
# 通过uniqid()实现重命名
$newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.');
$newDir= "uploads/".$newName;
# 文件名拓展名验证
$allow= array('image/jpeg','image/png','image/gif');
$ext= $_FILES['userfile']['type'];
if(!in_array($ext,$allow)){
echo '文件上传不合法';
exit;
}
# 上传服务处理
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
echo '上传有误';
echo '错误码:'.$_FILES['userfile']['error'];
exit;
}
}
?>
# upload.php
<?php
if(!empty($_POST)) {
# 判断是否存在目录
$dir= 'D:Program Filesxampphtdocsuploads';
if(!is_dir($dir)){
mkdir($dir);
}
# 通过uniqid()实现重命名
$newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.');
$newDir= "uploads/".$newName;
# 文件名拓展名验证
$info=finfo_open(FILEINFO_MIME_TYPE);
$ext= finfo_file($info, $_FILES['userfile']['tmp_name']);
$allow= array('image/jpeg','image/png','image/gif');
if(!in_array($ext,$allow)){
echo '文件上传不合法';
exit;
}
# 上传服务处理
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
echo '上传有误';
echo '错误码:'.$_FILES['userfile']['error'];
exit;
}
}
?>
- 优化文件上传
<?php
if(!empty($_POST)) {
# 判断是否存在目录
$dir= 'D:Program Filesxampphtdocsuploads';
if(!is_dir($dir)){
mkdir($dir);
}
# 通过uniqid()实现重命名
$newName= uniqid('goods_',true).strrchr($_FILES['userfile']['name'],'.');
$newDir= "uploads/".$newName;
# 文件名拓展名验证
$info=finfo_open(FILEINFO_MIME_TYPE);
$ext= finfo_file($info, $_FILES['userfile']['tmp_name']);
$allow= array('image/jpeg','image/png','image/gif');
if(!in_array($ext,$allow)){
echo '只能上传 '.implode(' , ',$allow).' 等文件格式';
exit;
}
# 验证文件大小
$fileSize= ini_get('upload_max_filesize');
if(substr($fileSize, -1, 1)== 'k'){
$fileSize= (integer)$fileSize* 1024;
}elseif(substr($fileSize, -1, 1)== 'M'){
$fileSize= (integer)$fileSize* 1024* 1024;
}elseif(substr($fileSize, -1, 1)== 'G'){
$fileSize= (integer)$fileSize* 1024* 1024* 1024;
}elseif(substr($fileSize, -1, 1)== 'T'){
$fileSize= (integer)$fileSize* 1024* 1024* 1024* 1024;
}
if($_FILES['userfile']['size']> $fileSize){
echo '文件大小不能超过'.number_format($fileSize/1024, 1).'K';
exit;
}
# 验证是否是http上传
if(!is_uploaded_file($_FILES['userfile']['tmp_name'])){
echo '文件不是HTTP POST上传的<br>';
exit;
}
# 上传服务处理
if($_FILES['userfile']['error']== 0){
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $newDir)){
echo "上传成功";
};
}else{
switch($_FILES['userfile']['error']) {
case 1:
echo '文件大小超过了php.ini中允许的最大值,最大值是:'.ini_get('upload_max_filesize');
break;
case 2:
echo '文件大小超过了表单允许的最大值';
break;
case 3:
echo '只有部分文件上传';
break;
case 4:
echo '没有文件上传';
break;
case 6:
echo '找不到临时文件';
break;
case 7:
echo '文件写入失败';
break;
default:
echo '未知错误';
break;
}
}
}
?>
文件下载
-
方法解释
__FILE__
当前文件的带文件名的绝对路径dirname(__FILE__)
返回路径中的目录部分iconv()
文件编码转换feof()
检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0
-
响应头设置
Content-type: application/octet-stream
指定文件类型Content-Disposition: attachment; filename={$file_name}
指定文件描述
<?php
header('Content-Type:text/html; charset=utf-8');
define('ROOT_PATH', dirname(__FILE__));
function downfile($file_path){
$file_path= iconv('utf-8', 'gb2312', $file_path);
if(!file_exists($file_path)){
exit('文件不存在!');
}
$file_name= basename($file_path);
$file_size= filesize($file_path);
$file= fopen($file_path, 'r');
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename={$file_name}");
$buffer= 1024;
$file_count= 0;
while(!feof($file) && ($file_size- $file_count> 0)){
$file_data= fread($file, $buffer);
$file_count+= $buffer;
echo $file_data;
}
fclose($file);
}
downfile(ROOT_PATH.".imgpigger.jpg");
?>