Correcting teacher:天蓬老师
Correction status:qualified
Teacher's comments:这应该是有史以来最完整的文件上传方案
multipart/form-data
类型$_FILES
记录上传的文件信息,$_FILES
二维键名为客户端form表单中的name属性值,其值是五个固定的文件信息序号 | 键名 | 描述 |
---|---|---|
1 | name |
文件在客户端的原始文件名(即存在用户电脑上的文件名) |
2 | type |
文件的 MIME 类型, 由浏览器提供, PHP 并不检查它 |
3 | tmp_name |
文件被上传到服务器上之后,在临时目录中临时文件名 |
4 | error |
和该文件上传相关的错误代码 |
5 | size |
已上传文件的大小(单位为字节) |
error
错误信息描述:
序号 | 常量 | 值 | 描述 |
---|---|---|---|
1 | UPLOAD_ERR_OK |
0 |
没有错误发生,文件上传成功 |
2 | UPLOAD_ERR_INI_SIZE |
1 |
文件超过php.ini 中upload_max_filesize 值 |
3 | UPLOAD_ERR_FORM_SIZE |
2 |
文件大小超过表单中MAX_FILE_SIZE 指定的值 |
4 | UPLOAD_ERR_PARTIAL |
3 |
文件只有部分被上传 |
5 | UPLOAD_ERR_NO_FILE |
4 |
没有文件被上传 |
6 | UPLOAD_ERR_NO_TMP_DIR |
6 |
找不到临时文件夹 |
7 | UPLOAD_ERR_CANT_WRITE |
7 |
文件写入失败 |
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>文件上传</title>
</head>
<style>
fieldset {
height: 100px;
padding: 20px 20px;
}
</style>
<body>
<form action="upload2.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>单文件上传</legend>
<input type="hidden" name="MAX_FILE_SIZE" value="500000" />
<input type="file" name="my_pic" />
<button>上传</button>
</fieldset>
</form>
<br />
<form action="upload2.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>多文件上传: 逐个上传</legend>
<input type="hidden" name="MAX_FILE_SIZE" value="300" />
<input type="file" name="my_pic1" />
<input type="file" name="my_pic2" />
<input type="file" name="my_pic3" />
<button>上传</button>
</fieldset>
</form>
<br />
<form action="upload2.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>多文件上传: 批量上传(限文件数)</legend>
<input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
<!-- 将name属性值能数组的形式提供 -->
<input type="file" name="my_pic[]" />
<input type="file" name="my_pic[]" />
<input type="file" name="my_pic[]" />
<button>上传</button>
</fieldset>
</form>
<br />
<form action="upload.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>多文件上传: 批量上传(不限数)</legend>
<input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
<!-- 将name属性值能数组的形式提供 -->
<input type="file" name="my_pic[]" multiple />
<button>上传</button>
</fieldset>
</form>
</body>
</html>
效果图:
<?php
class Upload
{
public static $path='uploads/';//设置文件保存位置
public static $rename=0;//设置是否重命名,0 否,其它值 是
public static $files = array();//保存成功上传的文件
public static $files_err = array();//保存上传失败的文件信息
public static $result = array("success"=>[],"error"=>[]);//记录保存结果
public static $error_code = '';//错误码
public static $specify_type=array();//指定上传文件的格式
const ERR_MESSAGE = ['没有错误发生,文件上传成功','文件超过`php.ini`中`upload_max_filesize`值','文件大小超过表单中`MAX_FILE_SIZE`指定的值',
'文件只有部分被上传','没有文件被上传','', '找不到临时文件夹','文件写入失败','文件格式错误'];
/**
* 获取所有上传的文件信息,转为二维数组
* $files,$files_err,分开保存上传成功和失败的文件
*/
public function __construct()
{
foreach($_FILES as $key=>$val){
//name如果是数组,循环获取数据,转为二维数组
if(is_array($val['name'])){
$count = count($val['name']);
for($i=0;$i<$count;$i++){
//判断是否以POST方式上传了文件
if($val['error'][$i]===0&&is_uploaded_file($val['tmp_name'][$i])){
self::$files[]=array(
'name'=>$val['name'][$i],
'type'=>$val['type'][$i],
'tmp_name'=>$val['tmp_name'][$i],
'error'=>$val['error'][$i],
'size'=>$val['size'][$i]
);
}else{
self::$files_err[]=array(
'name'=>$val['name'][$i],
'type'=>$val['type'][$i],
'tmp_name'=>$val['tmp_name'][$i],
'error'=>$val['error'][$i],
'size'=>$val['size'][$i]
);
}
}
}else{
//如果不是数组,直接获取数据
if($val['error']===0&&is_uploaded_file($val['tmp_name']))
{
self::$files[]=$val;
}else{
self::$files_err[]=$val;
}
}
}
}
/**
* 保存上传成功的文件,用户选择路径、是否重命名、限定文件类型
* $rename 重命名:0 否 ; 其它 是
*/
public function saveFile(string $path='uploads/',int $rename=0,array $specify_type=[]):array
{
self::$path=$path;
self::$rename=$rename;
self::$specify_type=$specify_type;
foreach(self::$files as $val){
$filename = $this->rename($val['name'],$rename);//重命名
if(!empty($specify_type)){
//如果不属于指定的类型,保存错误信息,跳出本次循环
if(!in_array($val['type'],$specify_type)){
self::$result['error'][] = $val['name'].":文件类型不符";
continue;
}
}
if(move_uploaded_file($val['tmp_name'], self::$path.$filename)){
self::$result['success'][] = $val['name'].':'.self::$path.$filename;
}else{
self::$result['error'][] = $val['name'].":保存失败";
}
}
return self::$result;
}
/**
* 按规则生成文件名
* $type : 0 否,其它 是
*/
public function rename(string $filename,int $type=0):string{
$suffix = strrchr($filename,'.');//后缀
$finalname = $filename;
//如果文件名存在,又不重新命名,就在原文件名后加(1)
if(file_exists(self::$path.$filename)&&$type===0){
$finalname = basename($filename,strrchr($filename,'.')).'(1)'.$suffix;
}elseif($type!==0){
$finalname = date('Ymd',time()).rand(1000,9999).$suffix;
}
if(file_exists(self::$path.$finalname)){//再次检测名称是否已存在(重新生成)
$finalname = $this->rename($filename,$type);
}
return $finalname;
}
}
$upload = new Upload;
print_r($upload::$files);//上传成功的文件
print_r($upload::$files_err);//上传失败的文件
print_r($upload->saveFile('uploads',1,['text/plain','image/jpeg']));
上传文件:
打印结果: