php实现文件上传功能
实现步骤
- 1.多文件上传格式化
file=>[‘name’=>[0=>’xx’,1=>’xx’],’type’=>[0=>’xx’,1=>’xx’]
格式化为:0=>[name=>’xx’,type=>’xx’] 2.检测可能发生的错误
1.上传文件错误(http://php.net/manual/zh/features.file-upload.php)
2.自定义限定错误(文件上传类型,大小,后缀名,是否是通过post上传)3.创建父目录和子目录、子文件名
- 4.移动文件到指定目录
- 5.返回上传信息
使用
<?php
require "Upload.php";
$config = [
'max_file_size' => 2097152,
'allow_mimes' => ['image/png', 'image/jpeg', 'image/jpg', 'image/gif',],
'allow_ext' => ['jpg', 'png', 'gif', 'jpeg'],
'root' => 'upload',
'sub_path' => 'sub',
'auto_sub_dir' => true,
'auto_sub_name' => false,
'save_sub_rule' => [
function ($value){
return $value.'world';},
'hello'],
];
$up = new Upload($config);
$res = $up->run();
// $res:
'code' => int 2000
'msg' => string '上传成功' (length=12)
'data' =>
array (size=8)
'name' => string 'xxx.jpeg' (length=26)
'key' => string 'file' (length=4)
'type' => string 'image/jpeg' (length=10)
'error' => int 0
'size' => int 123
'ext' => string 'jpg' (length=3)
'mime' => string 'image/jpeg' (length=10)
'path' => string '' (length=48)
代码
<?php
class Upload
{
private $_config = [
'max_file_size' => 2097152,
'allow_mimes' => [],
'allow_ext' => [],
'root' => 'uploads',
'sub_path' => '',
'auto_sub_dir' => true,
'auto_sub_name' => true,
'save_sub_rule' => ['date' , 'Y-m-d'],
];
private $_msg = '没有错误';
private $_fileInfo;
private $_cur_path;
public function __construct(array $config = [])
{
$this->_config = array_merge($this->_config, $config);
$this->_fileInfo = new finfo();
}
public function __get(string $name): string
{
if (!isset($this->_config[$name]) || empty($this->_config[$name])) {
$this->_msg = "获取失败,该配置选项不存在";
return $this->_msg;
}
return $this->_config[$name];
}
public function __set(string $name, string $value)
{
if (isset($this->_config[$name])) {
$this->_config[$name] = $value;
} else {
$this->_msg = "设置失败,该配置选项不存在";
}
}
public function getError(): string
{
return $this->_msg;
}
public function run(): array
{
$files = $_FILES;
$result = [
'code' => 4000,
'msg' => "上传失败",
'data' => [],
];
if (empty($files)) {
$this->_msg = "没有上传文件";
return $result;
}
$formatted_files = $this->format($files);
if (empty($formatted_files) || !is_array($formatted_files)) {
return $result;
}
foreach ($formatted_files as $item => $formatted_file) {
$result2[$item] = [
'code' => 4000,
'msg' => "上传失败",
'data' => [],
];
if (!$this->check($formatted_file)) {
$result2[$item]['msg'] = $this->_msg;
continue;
}
//创建或检测父目录
if (!$this->_config['root'] || !$this->createDir($this->_config['root'])) {
$this->_msg = '父目录创建失败或未填写父目录';
$result2[$item]['msg'] = $this->_msg;
continue;
}
//子目录
$parent_path = $this->_config['root'];
if ($this->_config['auto_sub_dir']) {
if (!$this->createSubDir($parent_path)) {
$result2[$item]['msg'] = $this->_msg;
continue;
}
} else {
if ($this->_config['sub_path'] && $this->createDir($parent_path . DIRECTORY_SEPARATOR . $this->_config['sub_path'])) {
$this->_cur_path = $parent_path . DIRECTORY_SEPARATOR . $this->_config['sub_path'];
} else {
$this->_cur_path = $parent_path;
}
}
//文件名称
$destination = $this->_cur_path . DIRECTORY_SEPARATOR;
if (!$this->_config['auto_sub_name']) {
$filename = $formatted_file['name'];
$destination .= $filename;
} else {
$filename = $this->getUniName();
$destination .= $filename . '.' . $formatted_file['ext'];
}
if (!move_uploaded_file($formatted_file['tmp_name'], $destination)) {
$this->_msg = "权限不足或其他原因,无法移动文件到指定目录" . $destination;
$result2[$item]['msg'] = $this->_msg;
continue;
}
//success
unset($formatted_file['tmp_name']);
$formatted_file['path'] = $destination;
$result2[$item]['data'] = $formatted_file;
$this->_msg = "上传成功";
$result2[$item]['code'] = 2000;
$result2[$item]['msg'] = $this->_msg;
}
return $result2??$result;
}
public function check(array $file): bool
{
$flag = false;
if (empty($file)) {
$this->_msg = "上传文件为空";
return $flag;
}
if (!is_array($file)) {
$this->_msg = "非法的上传文件";
return $flag;
}
if (!$this->getFileError($file['error'])) {
return $flag;
}
if (!is_uploaded_file($file['tmp_name'])) {
$this->_msg = "非法文件上传";
return $flag;
}
if (!$this->checkMime($file['mime'])) {
$this->_msg = "非法的mime类型";
return $flag;
}
if (!$this->checkExt($file['ext'])) {
$this->_msg = "非法的扩展名";
return $flag;
}
if (!$this->checkSize($file['size'])) {
$this->_msg = "上传文件大小符合要求";
return $flag;
}
$flag = true;
return $flag;
}
public function checkMime(string $mine): bool
{
return !$this->_config['allow_mimes'] ?: in_array($mine, $this->_config['allow_mimes']);
}
public function checkSize(int $size): bool
{
return ($this->_config['max_file_size'] > $size && $this->_config['max_file_size'] > 0);
}
public function checkExt(string $ext): bool
{
return !$this->_config['allow_ext'] ?: in_array($ext, $this->_config['allow_ext']);
}
public function getFileMime(string $name): string
{
return strtolower($this->_fileInfo->file($name, FILEINFO_MIME_TYPE));
}
public function getFileExt(string $name): string
{
return strtolower(pathinfo($name, PATHINFO_EXTENSION));
}
public function getUniName(): string
{
return md5(uniqid(microtime(true), true));
}
public function createDir(string $path): bool
{
return file_exists($path) ?: mkdir($path, 0777, true);
}
public function createSubDir(string $parent_path): bool
{
$rule = $this->_config['save_sub_rule'];
if (empty($rule)) {
$this->_msg = "请填写子目录规则";
return false;
}
$value = array_values($rule);
$sub_path = call_user_func($value[0],$value[1]);
$parent_path = str_replace('/', '', $parent_path);
$parent_path = str_replace('\\', '', $parent_path);
$this->_cur_path = $parent_path . DIRECTORY_SEPARATOR . $sub_path;
if (!$this->createDir($this->_cur_path)) {
$this->_msg = "创建子目录失败";
return false;
}
return true;
}
public function getFileError(string $no): bool
{
$flag = false;
switch ($no) {
case 0:
$flag = true;
$this->_msg = "文件上传成功";
break;
case 1:
$this->_msg = "上传的文件超过的php.ini中upload_max_size中限制的值";
break;
case 2:
$this->_msg = "上传的文件超过了HTML表单中max_file_size选项限制的值";
break;
case 3:
$this->_msg = "文件只有部分被上传";
break;
case 4:
$this->_msg = "没有文件被上传";
break;
case 6:
$this->_msg = "找不到临时文件";
break;
case 7:
$this->_msg = "文件写入失败";
break;
}
return $flag;
}
public function format(array $files): array
{
$formatted = [];
$order = 0;
foreach ($files as $item => $value) {
if (is_array($value['name'])) {
$order = count($value['name']);
$keys = array_keys($value);
for ($i = 0; $i < $order; $i++) {
foreach ($keys as $key) {
$formatted[$i][$key] = $value[$key][$i];
$formatted[$i]['key'] = $item;
}
$formatted[$i]['ext'] = !$value['name'][$i] ?: $this->getFileExt($value['name'][$i]);
$formatted[$i]['mime'] = !$value['name'][$i] ?: $this->getFileMime($value['tmp_name'][$i]);
}
} else {
$formatted[$order] = $value;
$formatted[$order]['key'] = $item;
}
}
return $formatted;
}
}