PHP 文件上传类及使用

时间:2025.6.20 编辑:SA 阅读量:1081 全屏 二维码链接 浏览等级:0级

<?php // 创建一个上传类 class upload { // 定义类中使用到的变量 private $error = ""; // 用于存储产生的错误信息 private $uploadFile = ""; // 存储客户端提交的文件信息 private $mimeType = "text/plain"; // 存储文件的mime值,默认为text/plain private $filterType = []; // 用于存放mime值的数组 private $Filter = []; // 用于存储可上传文件类型的变量 private $fileSize = 1024 * 1024; // 设置可上传文件大小(默认1MB) private $path = "html"; // 设置上传目录,默认值为html private $rename = true; // 设置重命名开关 private $ext = ""; // 用于存储文件扩展名 private $stat = false; // 用于存储文件上传状态 // 构造函数,初始化类 public function __construct($files, $path = "html", $rename = true) { $this->path = $path; // 设置上传路径 $this->filterType(); // 设置$filterType数组 $this->Filter(); // 设置$Filter数组 $this->uploadFile = $files; // 设置上传文件 $this->rename = $rename; // 设置重命名开关 $this->uploadFile(); // 开始上传文件 } // 上传文件函数 public function uploadFile() { $file = $this->uploadFile; // 获取类初始化时关于上传文件的数据 if (isset($file["tmp_name"]) && file_exists($file["tmp_name"])) { // 检测上传文件变量中是否存在上传文件数据 $tmp = $file["tmp_name"]; // 获取上传文件临时文件名 $name = $file["name"]; // 获取上传文件名称 $dir = $this->path; // 设置文件保存目录 // 确保上传目录存在 if (!is_dir($dir)) { mkdir($dir, 0777, true); } // 检查上传文件是否合法 if (!$this->checkFileType($name, $tmp)) { return false; // 如果上传文件类型为非法文件类型,返回false值 } if (!$this->checkFileSize($tmp)) { return false; // 如果上传文件过大,返回false值 } // 根据重命名开关,处理新文件名 if ($this->rename) { $filename = $this->newName() . "." . $this->ext; } else { $filename = $file["name"]; } // 安全处理文件名,防止目录遍历攻击 $safeFilename = basename($filename); $destination = $dir . "/" . $safeFilename; // 移动上传的临时文件到新目录 if (move_uploaded_file($tmp, $destination)) { $this->stat = true; // 设置上传状态为true return true; } else { $this->stat = false; // 设置上传状态为false $this->error .= "文件上传失败!<br>"; return false; } } else { $this->error .= "上传文件不存在!<br>"; return false; } } // 创建新文件名 private function newName() { return uniqid() . time(); // 返回唯一ID和时间戳组合作为新文件名 } // 设置上传文件大小 public function setFileSize($size) { $this->fileSize = $size; // 设置类的关于文件大小的值 } // 检查文件大小是否合法 private function checkFileSize($file) { $filesize = filesize($file); // 获取文件大小 if ($filesize <= $this->fileSize) { // 检测文件大小是否小于等于规定的文件大小 return true; } else { $this->error .= "上传文件大于设置文件大小!"; return false; // 当上传文件大于规定的大小时,返回false值 } } // 检查文件类型 private function checkFileType($filename, $file) { // 取得文件的扩展名 $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $this->ext = $ext; // 检查上传文件的扩展名是否在允许的列表中 if (in_array($ext, $this->Filter)) { // 使用fileinfo扩展获取MIME类型(更安全) if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->mimeType = finfo_file($finfo, $file); finfo_close($finfo); } elseif (function_exists("mime_content_type")) { // 如果mime_content_type()函数存在,使用其取得文件的mime值 $this->mimeType = mime_content_type($file); } else { // 如果上述函数都不存在,使用预定义的MIME类型映射 if (isset($this->filterType[$ext])) { $this->mimeType = $this->filterType[$ext]; } } // 如果获取mime值后,$this->mimeType值依然为空,显示错误信息 if (empty($this->mimeType)) { $this->error .= "获取文件类型出错"; return false; } else { return true; } } else { $this->error .= "此文件类型不允许上传!<br>"; return false; } } // 文件上传统计 public function saveUpload() { // 这里可以添加文件上传记录到数据库或日志的代码 } // 取得错误信息 public function getError() { return $this->error; } // 设置允许上传的文件扩展名 private function Filter() { // 默认允许上传txt和zip文件,用户可以扩展这个列表 $this->Filter = array("txt", "zip", "jpg", "png", "gif"); } // 用于填充$this->filterType数组 private function filterType() { $this->filterType = array( 'chm' => 'application/octet-stream', 'ppt' => 'application/vnd.ms-powerpoint', 'xls' => 'application/vnd.ms-excel', 'doc' => 'application/msword', 'exe' => 'application/octet-stream', 'rar' => 'application/octet-stream', 'zip' => 'application/zip', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'txt' => 'text/plain' ); } } // 检查上传请求 if (isset($_GET["action"]) && $_GET["action"] == "upload") { // 确保上传目录存在 if (!is_dir("html")) { mkdir("html", 0777, true); } // 初始化upload类 $up = new upload($_FILES["file"], "html", true); // 设置最大上传文件大小为10MB $up->setFileSize(10 * 1024 * 1024); // 如果文件上传成功,显示上传成功信息 if ($up->stat) { echo "文件上传成功!"; exit(); } else { // 如果上传失败,显示错误信息 echo $up->getError(); exit(); } } ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>上传文件</title> </head> <body> <form action="?action=upload" method="post" enctype="multipart/form-data" name="sendfile"> <label>选择上传文件: <input type="file" name="file" /> </label> <label> <input type="submit" name="Submit" value="上传" /> </label> </form> </body> </html>



<?php // 创建一个下载类 class download { // 定义类中使用到的变量 private $error = ""; // 用于存储产生的错误信息 private $downFile = ""; // 存储下载文件名称 private $mimeType = "text/plain"; // 存储下载文件的mime值,默认为text/plain private $filterType = []; // 用于存放mime值的数组 private $Filter = []; // 用于存储可下载文件类型的变量 // 构造函数,初始化类 public function __construct($filename) { $this->filterType(); // 设置$filterType数组 $this->Filter(); // 设置$Filter数组 $this->downFile = $filename; // 设置下载文件 $this->downFile(); // 下载文件 } // 下载文件函数 public function downFile() { // 使用checkFileType()函数检查下载文件是否合法 if ($this->checkFileType()) { $filename = basename($this->downFile); // 安全获取文件名 // 输出头信息 header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Content-Type: " . $this->mimeType); // 输出文件类型头信息 header("Content-Length: " . filesize($this->downFile)); // 输出文件大小头信息 header("Content-Disposition: attachment; filename=\"" . $filename . "\""); // 文件名称头信息 header("Content-Transfer-Encoding: binary"); // 以二进制方式编码数据 // 输出文件内容 readfile($this->downFile); return true; } else { return false; } } // 检查文件类型 private function checkFileType() { // 检查下载的文件是否存在 if (file_exists($this->downFile)) { // 取得文件的扩展名 $ext = strtolower(pathinfo($this->downFile, PATHINFO_EXTENSION)); // 检查下载文件的扩展名是否在允许的列表中 if (in_array($ext, $this->Filter)) { // 使用fileinfo扩展获取MIME类型(更安全) if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->mimeType = finfo_file($finfo, $this->downFile); finfo_close($finfo); } elseif (function_exists("mime_content_type")) { // 如果mime_content_type()函数存在,使用其取得文件的mime值 $this->mimeType = mime_content_type($this->downFile); } else { // 如果上述函数都不存在,使用预定义的MIME类型映射 if (isset($this->filterType[$ext])) { $this->mimeType = $this->filterType[$ext]; } } // 如果获取mime值后,$this->mimeType值依然为空,显示错误信息 if (empty($this->mimeType)) { $this->error .= "获取文件类型出错"; return false; } else { return true; } } else { $this->error .= "此文件类型不允许下载!<br>"; return false; } } else { $this->error .= "文件不存在!<br>"; return false; } } // 文件下载统计 public function countDownload() { // 注意:原代码中的统计逻辑会破坏文件内容 // 这里提供一个安全的统计方式示例 $logFile = __DIR__ . '/download_log.txt'; $count = 1; // 如果日志文件存在,读取当前计数 if (file_exists($logFile)) { $count = (int)file_get_contents($logFile) + 1; } // 更新计数 file_put_contents($logFile, $count); } // 取得错误信息 public function getError() { return $this->error; // 返回错误信息 } // 设置允许下载的文件扩展名 private function Filter() { // 默认允许下载txt文件,用户可以扩展这个列表 $this->Filter = array("txt", "pdf", "jpg", "png", "zip", "rar"); } // 用于填充$this->filterType数组 private function filterType() { $this->filterType = array( 'chm' => 'application/octet-stream', 'ppt' => 'application/vnd.ms-powerpoint', 'xls' => 'application/vnd.ms-excel', 'doc' => 'application/msword', 'exe' => 'application/octet-stream', 'rar' => 'application/octet-stream', 'zip' => 'application/zip', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'txt' => 'text/plain', 'pdf' => 'application/pdf' ); } } // 创建一个数组,数组中包含着要下载文件的地址 $files = array( 1 => array("html/1.txt", "示例文本文件"), 2 => array("html/sample.pdf", "示例PDF文件"), 3 => array("html/image.jpg", "示例图片") ); // 检查下载请求 if (isset($_GET["action"]) && $_GET["action"] == "download") { $fid = intval($_GET["fid"]); // 取得数组的键值 // 验证文件ID是否存在 if (isset($files[$fid])) { $filename = $files[$fid][0]; // 根据键值取得下载文件名称 // 安全检查:确保文件在允许的目录内 $safeDir = realpath(__DIR__ . '/html'); $requestedFile = realpath(__DIR__ . '/' . $filename); if (strpos($requestedFile, $safeDir) === 0) { $down = new download($filename); // 初始化download类 // 记录下载统计 $down->countDownload(); // 如果下载成功,结束代码运行 if ($down->downFile()) { exit(); } else { // 如果下载失败,显示错误信息 echo $down->getError(); exit(); } } else { echo "访问被拒绝: 非法文件路径!"; exit(); } } else { echo "文件不存在!"; exit(); } } ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>文件下载</title> </head> <body> <h3>直接下载文件的方式</h3> <?php foreach ($files as $key => $val): ?> <p><a href="<?php echo htmlspecialchars($val[0]); ?>" download><?php echo htmlspecialchars($val[1]); ?></a></p> <?php endforeach; ?> <h3>通过服务器中转下载的方式</h3> <?php foreach ($files as $key => $val): ?> <p><a href="?action=download&fid=<?php echo $key; ?>"><?php echo htmlspecialchars($val[1]); ?></a></p> <?php endforeach; ?> </body> </html>