1.单文件上传,自定义异常类来处理常见错误
- 对错误编码的判断
- 判断文件类型是否正确
- 判断上传方式是否正确
| 序号 | 常量 | 值 | 描述
| 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` | 文件写入失败 |
- 以下举了一些上传错误的例子
<?php
error_reporting(E_ALL);
// $_FILES: 文件上传变量,超全局的变量数组, 保存着所有与文件上传的相关信息
printf('<pre>%s</pre>', print_r($_FILES, true));
// 自定义文件上传的异常处理类
class UploadException extends Exception
{
public function __toString()
{
return <<< UPLOAD
<table>
<tr>
<td>编号</td>
<td>信息</td>
<td>文件</td>
<td>行号</td>
</tr>
<tr>
<td>$this->code</td>
<td>$this->message</td>
<td>$this->file</td>
<td>$this->line</td>
</tr>
</table>
<style>
table {border-collapse: collapse;border:1px solid black;text-align: center;}
td {border:1px solid black;padding: 5px;}
tr:first-of-type {background-color:#eee;}
tr:last-of-type td {color: red;}
</style>
UPLOAD;
}
}
try {
// 对错误编码的判断
$errorCode = $_FILES['my_pic']['error'] ?? null;
// 使用系统常量进行判断
if ($errorCode > UPLOAD_ERR_OK) {
switch ($errorCode) {
case UPLOAD_ERR_INI_SIZE:
throw new UploadException('上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值',1);
break;
case UPLOAD_ERR_FORM_SIZE:
throw new UploadException('上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值', 2);
break;
case UPLOAD_ERR_PARTIAL:
throw new UploadException('文件只有部分被上传', 3);
break;
case UPLOAD_ERR_NO_FILE:
throw new UploadException('没有文件被上传', 4);
break;
case UPLOAD_ERR_NO_TMP_DIR:
throw new UploadException('找不到临时文件夹', 5);
break;
case UPLOAD_ERR_CANT_WRITE:
throw new UploadException('文件写入失败', 6);
break;
default:
// 测试时建议关掉default: 避免误报影响
throw new UploadException('未知类型错误', 7);
}
}
// 判断文件类型是否正确
$fileType = $_FILES['my_pic']['type'] ?? null;
$type = strstr($fileType, '/', true); // "image"
// var_dump($fileType);
// 不为null时,取反
if (!is_null($fileType)) {
if ($type !== 'image') throw new UploadException('文件类型错误', 8);
}
// 判断上传方式是否正确
// 临时文件名
$tmplFileName = $_FILES['my_pic']['tmp_name'] ?? null;
// 首先临时文件是存在的,并且必须是通过POST上传的
if ($tmplFileName && is_uploaded_file($tmplFileName)) throw new UploadException('上传类型错误', 9);
} catch (UploadException $e) {
echo $e;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传的异常处理</title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>单文件上传</legend>
<!-- 隐藏域设置上传文件大小,必须写到input:file之前 -->
<!-- 前端拦截 -->
<input type="hidden" name="MAX_FILE_SIZE" value="38000">
<input type="file" name="my_pic" id="">
<button>上传</button>
</fieldset>
</form>
</body>
</html>
2.多文件批量上传及异常处理操作
<?php
error_reporting(E_ALL);
printf('<pre>%s</pre>', print_r($_FILES, true));
// // 自定义文件上传的异常处理类
class UploadException extends Exception
{
public function __toString()
{
return <<< UPLOAD
<table>
<tr>
<td>编号</td>
<td>信息</td>
<td>文件</td>
<td>行号</td>
</tr>
<tr>
<td>$this->code</td>
<td>$this->message</td>
<td>$this->file</td>
<td>$this->line</td>
</tr>
</table>
<style>
table {border-collapse: collapse;border:1px solid black;text-align: center;}
td {border:1px solid black;padding: 5px;}
tr:first-of-type {background-color:#eee;}
tr:last-of-type td {color: red;}
</style>
UPLOAD;
}
}
try {
// 对错误编码的判断
$errorCode = $_FILES['my_pic']['error'] ?? null;
// 使用系统常量进行判断
if ($errorCode > UPLOAD_ERR_OK) {
switch ($errorCode) {
case UPLOAD_ERR_INI_SIZE:
throw new UploadException('上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值',1);
break;
case UPLOAD_ERR_FORM_SIZE:
throw new UploadException('上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值', 2);
break;
case UPLOAD_ERR_PARTIAL:
throw new UploadException('文件只有部分被上传', 3);
break;
case UPLOAD_ERR_NO_FILE:
throw new UploadException('没有文件被上传', 4);
break;
case UPLOAD_ERR_NO_TMP_DIR:
throw new UploadException('找不到临时文件夹', 5);
break;
case UPLOAD_ERR_CANT_WRITE:
throw new UploadException('文件写入失败', 6);
break;
default:
// 测试时建议关掉default: 避免误报影响
throw new UploadException('未知类型错误', 7);
}
}
// 判断文件类型是否正确
$fileType = $_FILES['my_pic']['type'] ?? null;
$type = strstr($fileType, '/', true); // "image"
if (!is_null($fileType)) {
if ($type !== 'image') throw new UploadException('文件类型错误', 8);
}
// 判断上传方式是否正确
// 临时文件名tmplFileName
$tmplFileName = $_FILES['my_pic']['tmp_name'] ?? null;
// 1. 首先临时文件是存在的,并且必须是通过POST上传的
if ($tmplFileName && is_uploaded_file($tmplFileName)) {
// 2. 将文件从临时目录移动到目标目录中: uploads/
// move_uploaded_file(临时文件, 目标文件名)
// 原始文件名originalFileName
$originalFileName = $_FILES['my_pic']['name'] ?? null;
echo strstr($originalFileName, '.');
// 目标文件名destFileName,如果上传重复了,就得把文件名加密处理,生成随时字符串
$destFileName = 'uploads/' . md5(time(). mt_rand(1,1000)) .strstr($originalFileName, '.');
// 将临时文件上传到目标文件
if (move_uploaded_file($tmplFileName, $destFileName)) {
echo '<p>'. $_FILES['my_pic']['name'].': 上传成功</p>';
// 预览图片
echo "<img src='{$destFileName}' width='200'>";
}
}
} catch (UploadException $e) {
echo $e;
}
// 多文件上传
foreach ($_FILES as $file) {
// print_r($file);
// 判断 $file['error'] 是否为0,如果为0表示上传成功
if ($file['error'] === 0) {
$destFileName = 'uploads/' . md5(time(). mt_rand(1,1000)) .strstr($file['name'], '.');
if (move_uploaded_file($file['tmp_name'], $destFileName)) {
echo '<p>'. $file['name'].': 上传成功</p>';
// 预览图片
echo "<img src='{$destFileName}' width='200'>";
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多文件上传</title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>批量上传文件</legend>
<!-- 隐藏域设置上传文件大小,必须写到input:file之前 -->
<!-- <input type="hidden" name="MAX_FILE_SIZE" value="38000"> -->
<input type="file" name="my_pic1" id="">
<input type="file" name="my_pic2" id="">
<input type="file" name="my_pic3" id="">
<button>上传</button>
</fieldset>
</form>
</body>
</html>
-总结:
- 单文件上传,有7种错误要进行判断
- 文件必须是通过POST上传的
- 多文件上传,批量上传,文件上传类中同样要做8种错误判断
- 上传重复图片时,就得把文件名加密处理,生成随时字符串,uploads目录里就会自动生成不同的串码