
下面是一个完整的PHP单文件上传类实现,包含了安全验证、文件类型检查、大小限制等功能。
文件上传类完整代码
<?php/**
* 单文件上传类
*/class FileUploader {
// 上传配置
private $config = array(
'maxSize' => 2097152, // 2MB
'allowExts' => array('jpg', 'gif', 'png', 'jpeg'),
'savePath' => './uploads/',
'autoSub' => true, // 自动子目录存储
'subType' => 'date', // 子目录创建方式 date|hash|custom
'dateFormat'=> 'Ymd',
'hashLevel' => 1, // hash子目录层级
'replace' => false, // 存在同名文件是否覆盖
'saveName' => array('uniqid', ''), // 保存文件名规则
'autoCheck' => true, // 是否自动检查附件
);
// 上传文件信息
private $fileInfo = array();
// 错误信息
private $error = '';
/**
* 构造函数
* @param array $config 上传配置
*/
public function __construct($config = array()) {
$this->config = array_merge($this->config, $config);
}
/**
* 上传文件
* @param string $field 文件字段名
* @return bool|string 成功返回文件路径,失败返回false
*/
public function upload($field) {
// 检查上传文件
if (!isset($_FILES[$field])) {
$this->error = '没有文件被上传';
return false;
}
$file = $_FILES[$field];
// 检查上传错误
if ($file['error']) {
$this->error = $this->getErrorMsg($file['error']);
return false;
}
// 检查是否HTTP上传
if (!is_uploaded_file($file['tmp_name'])) {
$this->error = '非法上传文件';
return false;
}
// 收集文件信息
$this->fileInfo = array(
'name' => $file['name'],
'type' => $file['type'],
'tmp_name' => $file['tmp_name'],
'size' => $file['size'],
'ext' => $this->getExt($file['name'])
);
// 自动检查文件
if ($this->config['autoCheck']) {
if (!$this->check()) {
return false;
}
}
// 创建保存目录
$savePath = $this->getSavePath();
if (!is_dir($savePath)) {
if (!mkdir($savePath, 0755, true)) {
$this->error = '上传目录不存在或不可写';
return false;
}
}
// 生成保存文件名
$saveName = $this->getSaveName();
$filename = $savePath . $saveName;
// 移动文件
if (!move_uploaded_file($file['tmp_name'], $filename)) {
$this->error = '文件移动失败';
return false;
}
return str_replace('\\', '/', $filename);
}
/**
* 获取错误信息
* @return string
*/
public function getError() {
return $this->error;
}
/**
* 获取上传文件信息
* @return array
*/
public function getFileInfo() {
return $this->fileInfo;
}
/**
* 检查上传文件
* @return bool
*/
private function check() {
// 检查文件大小
if ($this->fileInfo['size'] > $this->config['maxSize']) {
$this->error = '上传文件大小超过限制';
return false;
}
// 检查文件类型
if (!in_array(strtolower($this->fileInfo['ext']), $this->config['allowExts'])) {
$this->error = '上传文件类型不允许';
return false;
}
// 检查文件是否合法
if (!$this->checkFile()) {
$this->error = '上传文件内容不合法';
return false;
}
return true;
}
/**
* 检查文件内容是否合法
* @return bool
*/
private function checkFile() {
// 简单的图片文件检查
if (in_array(strtolower($this->fileInfo['ext']), array('jpg', 'jpeg', 'gif', 'png', 'bmp'))) {
$imgInfo = @getimagesize($this->fileInfo['tmp_name']);
if (!$imgInfo || !in_array($imgInfo[2], array(1, 2, 3, 6))) {
return false;
}
}
return true;
}
/**
* 获取文件扩展名
* @param string $filename
* @return string
*/
private function getExt($filename) {
return pathinfo($filename, PATHINFO_EXTENSION);
}
/**
* 获取保存路径
* @return string
*/
private function getSavePath() {
$path = rtrim($this->config['savePath'], '/') . '/';
if ($this->config['autoSub']) {
switch ($this->config['subType']) {
case 'date':
$path .= date($this->config['dateFormat']) . '/';
break;
case 'hash':
$name = md5($this->fileInfo['name']);
for ($i = 0; $i < $this->config['hashLevel']; $i++) {
$path .= substr($name, 0, 2) . '/';
$name = substr($name, 2);
}
break;
case 'custom':
$path .= call_user_func($this->config['subType']) . '/';
break;
}
}
return $path;
}
/**
* 生成保存文件名
* @return string
*/
private function getSaveName() {
$saveName = $this->fileInfo['name'];
if (is_array($this->config['saveName'])) {
$func = $this->config['saveName'][0];
$param = $this->config['saveName'][1];
if ($func) {
$saveName = $func($param) . '.' . $this->fileInfo['ext'];
}
}
// 如果存在同名文件且不覆盖,则重命名
if (!$this->config['replace'] && file_exists($this->getSavePath() . $saveName)) {
$saveName = uniqid() . '.' . $this->fileInfo['ext'];
}
return $saveName;
}
/**
* 获取上传错误信息
* @param int $errorNo
* @return string
*/
private function getErrorMsg($errorNo) {
switch ($errorNo) {
case 1:
return '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值';
case 2:
return '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值';
case 3:
return '文件只有部分被上传';
case 4:
return '没有文件被上传';
case 6:
return '找不到临时文件夹';
case 7:
return '文件写入失败';
default:
return '未知上传错误';
}
}}使用示例
<?php// 引入上传类require_once 'FileUploader.php';// 配置上传参数$config = array(
'maxSize' => 5242880, // 5MB
'allowExts' => array('jpg', 'gif', 'png', 'jpeg'),
'savePath' => './uploads/',
'saveName' => array('uniqid', ''), // 使用唯一文件名);// 实例化上传类$uploader = new FileUploader($config);// 执行上传$result = $uploader->upload('file'); // 'file'是表单中的文件字段名if ($result) {
echo "文件上传成功,保存路径:".$result;} else {
echo "文件上传失败:".$uploader->getError();}HTML表单示例
<!DOCTYPE html><html><head> <title>文件上传示例</title></head><body> <form action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上传"> </form></body></html>
功能特点
安全性验证:检查是否为合法上传文件
文件类型限制:可配置允许上传的文件类型
大小限制:可配置最大上传文件大小
自动子目录:支持按日期、hash等方式自动创建子目录
唯一文件名:防止文件名冲突
错误处理:提供详细的错误信息
图片验证:对图片文件进行简单的内容验证
这个类可以满足大多数单文件上传需求,使用时只需简单配置即可。
希望以上内容对你有所帮助!如果还有其他问题,请随时提问。 各类知识收集 拥有多年CMS企业建站经验,对 iCMS, LeCMS, ClassCMS, Fastadmin, PbootCMS, PHPCMS, 易优CMS, YzmCMS, 讯睿CMS, 极致CMS, Wordpress, HkCMS, YznCMS, WellCMS, ThinkCMF, 等各类cms的相互转化,程序开发,网站制作,bug修复,程序杀毒,插件定制都可以提供最佳解决方案。


