- 上传的文件保存在临时文件夹中,如没有另外保存,脚本结束后就没了
- 大文件上传,如50M以上的,除了php.ini还需要配置apache中httpd.conf文件里FcgidMaxRequestLen 的值,不然会出现Internal Server Error
基本概念
1.客户端上传
- html中用户可以通过form表单上传文件,
- form表单中input标签的type属性设置为file时,即规定输入内容作为文件处理。
- 表单的上传方式必须是POST
- enctype属性规定上传的内容类型,文件使用
multipart/form-data
类型 - 文件上传的方式有单文件上传和多文件上传,
- 多文件上传又分为三种类型:
- 1.逐一上传,表单中每个input的name属性值不同
- 2.批量上传,限定文件个数,每个input的name属性值相同为数组类型,每次可选 一个文件
- 3.批量上传,不限定个数,input的name属性值为数组类型,并添加multiple属 性,可以同时选多个文件
2.服务器处理
- PHP中以全局变量
$_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()
方法保存到指定位置
示例演示
1.创建上传页面
- 创建4种不同上传方式的form表单
<!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>
效果图:
" class="reference-link">
" class="reference-link">
2.创建PHP上传文件处理类
- 通过构造函数把多文件上传的文件信息保存到二维数组中
- self::$files保存上传成功的文件信息,self::$files_err保存上传失败的文件信息
- 然后可以通过saveFile()方法保存上传成功的文件到指定位置
<?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']));
3.演示截图
上传文件:
打印结果: