PHP建站技术分享-从入门到精通_各类知识收集PHP建站技术分享-从入门到精通_各类知识收集PHP建站技术分享-从入门到精通_各类知识收集

QQ:420220301 微信/手机:150-3210-7690
当前位置:首页 > 工作总结

PHP实现文件上传下载实例

管理员 2025-03-26
工作总结
38

下面我将提供一个完整的PHP文件上传与下载的实现方案,包含前端表单、后端处理代码和安全措施。

文件上传实现

1. 前端HTML表单

html
复制
<!DOCTYPE html><html><head>
    <title>文件上传与下载</title></head><body>
    <h2>文件上传</h2>
    <form action="upload.php" method="post" enctype="multipart/form-data">
        <input type="file" name="fileToUpload" id="fileToUpload">
        <input type="submit" value="上传文件" name="submit">
    </form>
    
    <h2>文件下载</h2>
    <?php
    // 显示可下载文件列表
    $files = scandir('uploads');
    foreach($files as $file) {
        if($file !== '.' && $file !== '..') {
            echo "<p><a href='download.php?file=".urlencode($file)."'>$file</a></p>";
        }
    }
    ?></body></html>

2. 文件上传处理 (upload.php)

php
复制
<?php// 上传目录$uploadDir = 'uploads/';// 创建上传目录(如果不存在)if (!file_exists($uploadDir)) {
    mkdir($uploadDir, 0777, true);}// 检查文件是否上传成功if(isset($_POST["submit"])) {
    $targetFile = $uploadDir . basename($_FILES["fileToUpload"]["name"]);
    $uploadOk = 1;
    $fileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
    
    // 检查文件是否已存在
    if (file_exists($targetFile)) {
        echo "抱歉,文件已存在。";
        $uploadOk = 0;
    }
    
    // 限制文件大小 (5MB)
    if ($_FILES["fileToUpload"]["size"] > 5000000) {
        echo "抱歉,文件太大。";
        $uploadOk = 0;
    }
    
    // 允许的文件格式
    $allowedTypes = array('jpg', 'png', 'jpeg', 'gif', 'pdf', 'doc', 'docx', 'txt');
    if(!in_array($fileType, $allowedTypes)) {
        echo "抱歉,只允许上传 JPG, JPEG, PNG, GIF, PDF, DOC, DOCX, TXT 文件。";
        $uploadOk = 0;
    }
    
    // 检查上传标志
    if ($uploadOk == 0) {
        echo "抱歉,文件未上传。";
    } else {
        // 尝试上传文件
        if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) {
            echo "文件 ". htmlspecialchars(basename($_FILES["fileToUpload"]["name"])). " 上传成功。";
            // 重定向回上传页面
            header("Refresh: 2; URL=index.php");
        } else {
            echo "抱歉,上传文件时出错。";
        }
    }}?>

3. 文件下载处理 (download.php)

php
复制
<?php// 下载目录(必须与上传目录相同)$downloadDir = 'uploads/';if(isset($_GET['file'])) {
    $fileName = basename($_GET['file']);
    $filePath = $downloadDir . $fileName;
    
    // 检查文件是否存在
    if(file_exists($filePath)) {
        // 设置适当的头部信息
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($filePath).'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($filePath));
        
        // 清除输出缓冲
        flush();
        
        // 读取文件并输出到浏览器
        readfile($filePath);
        exit;
    } else {
        http_response_code(404);
        die('文件不存在');
    }} else {
    die('无效的文件名');}?>

安全增强措施

1. 文件上传安全增强

php
复制
// 在upload.php中添加以下检查// 检查文件是否是真实的图片(仅对图片有效)if(isset($_POST["submit"])) {
    $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
    if($check !== false) {
        // 是图片
    } else {
        echo "文件不是图片。";
        $uploadOk = 0;
    }}// 防止文件名注入攻击$fileName = preg_replace("/[^A-Za-z0-9\.]/", "", $_FILES["fileToUpload"]["name"]);$targetFile = $uploadDir . $fileName;// 生成随机文件名$newFileName = uniqid() . '.' . $fileType;$targetFile = $uploadDir . $newFileName;

2. 文件下载安全增强

php
复制
// 在download.php中添加以下检查// 防止目录遍历攻击$fileName = basename($_GET['file']);$filePath = realpath($downloadDir . $fileName);// 确保文件在指定目录内if(strpos($filePath, realpath($downloadDir)) !== 0) {
    die('非法文件访问');}// 检查文件类型并提供正确的Content-Type$fileExtension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));$contentTypes = [
    'jpg'  => 'image/jpeg',
    'jpeg' => 'image/jpeg',
    'png'  => 'image/png',
    'gif'  => 'image/gif',
    'pdf'  => 'application/pdf',
    'doc'  => 'application/msword',
    'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'txt'  => 'text/plain'];if(array_key_exists($fileExtension, $contentTypes)) {
    header('Content-Type: ' . $contentTypes[$fileExtension]);} else {
    header('Content-Type: application/octet-stream');}

完整类封装版本

文件上传下载类 (FileHandler.php)

php
复制
<?phpclass FileHandler {
    private $uploadDir;
    private $allowedTypes;
    private $maxFileSize;
    
    public function __construct($uploadDir = 'uploads/', $allowedTypes = array(), $maxFileSize = 5000000) {
        $this->uploadDir = rtrim($uploadDir, '/') . '/';
        $this->allowedTypes = $allowedTypes ?: array('jpg', 'png', 'jpeg', 'gif', 'pdf', 'doc', 'docx', 'txt');
        $this->maxFileSize = $maxFileSize;
        
        // 创建上传目录
        if (!file_exists($this->uploadDir)) {
            mkdir($this->uploadDir, 0777, true);
        }
    }
    
    public function upload($fileInputName) {
        if (!isset($_FILES[$fileInputName])) {
            return ['success' => false, 'message' => '没有文件被上传'];
        }
        
        $file = $_FILES[$fileInputName];
        
        // 检查上传错误
        if ($file['error'] !== UPLOAD_ERR_OK) {
            return ['success' => false, 'message' => $this->getUploadError($file['error'])];
        }
        
        // 检查文件大小
        if ($file['size'] > $this->maxFileSize) {
            return ['success' => false, 'message' => '文件太大'];
        }
        
        // 获取文件扩展名
        $fileExt = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        
        // 检查文件类型
        if (!in_array($fileExt, $this->allowedTypes)) {
            return ['success' => false, 'message' => '不允许的文件类型'];
        }
        
        // 生成安全文件名
        $safeName = $this->generateSafeName($file['name']);
        $targetPath = $this->uploadDir . $safeName;
        
        // 移动上传的文件
        if (move_uploaded_file($file['tmp_name'], $targetPath)) {
            return [
                'success' => true,
                'message' => '文件上传成功',
                'filePath' => $targetPath,
                'fileName' => $safeName
            ];
        } else {
            return ['success' => false, 'message' => '文件移动失败'];
        }
    }
    
    public function download($fileName) {
        $filePath = realpath($this->uploadDir . basename($fileName));
        
        // 安全检查
        if (!file_exists($filePath)) {
            return ['success' => false, 'message' => '文件不存在'];
        }
        
        if (strpos($filePath, realpath($this->uploadDir)) !== 0) {
            return ['success' => false, 'message' => '非法文件访问'];
        }
        
        // 获取文件信息
        $fileExt = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        $fileSize = filesize($filePath);
        $contentType = $this->getContentType($fileExt);
        
        // 设置头部信息
        header('Content-Description: File Transfer');
        header('Content-Type: ' . $contentType);
        header('Content-Disposition: attachment; filename="'.basename($filePath).'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . $fileSize);
        
        // 输出文件
        readfile($filePath);
        exit;
    }
    
    public function listFiles() {
        $files = scandir($this->uploadDir);
        return array_filter($files, function($file) {
            return $file !== '.' && $file !== '..';
        });
    }
    
    private function generateSafeName($fileName) {
        $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        $baseName = md5(uniqid() . microtime(true));
        return $baseName . '.' . $extension;
    }
    
    private function getUploadError($errorCode) {
        $errors = [
            UPLOAD_ERR_INI_SIZE => '文件超过了php.ini中upload_max_filesize限制',
            UPLOAD_ERR_FORM_SIZE => '文件超过了表单MAX_FILE_SIZE限制',
            UPLOAD_ERR_PARTIAL => '文件只有部分被上传',
            UPLOAD_ERR_NO_FILE => '没有文件被上传',
            UPLOAD_ERR_NO_TMP_DIR => '找不到临时文件夹',
            UPLOAD_ERR_CANT_WRITE => '文件写入失败',
            UPLOAD_ERR_EXTENSION => 'PHP扩展阻止了文件上传'
        ];
        return $errors[$errorCode] ?? '未知上传错误';
    }
    
    private function getContentType($extension) {
        $types = [
            'jpg'  => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'png'  => 'image/png',
            'gif'  => 'image/gif',
            'pdf'  => 'application/pdf',
            'doc'  => 'application/msword',
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'txt'  => 'text/plain'
        ];
        return $types[$extension] ?? 'application/octet-stream';
    }}

使用封装类

php
复制
<?php// 使用示例require_once 'FileHandler.php';// 初始化文件处理器$fileHandler = new FileHandler('uploads/', ['jpg', 'png', 'pdf'], 2 * 1024 * 1024); // 2MB限制// 处理上传if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
    $result = $fileHandler->upload('fileToUpload');
    if ($result['success']) {
        echo "文件上传成功: " . $result['fileName'];
    } else {
        echo "上传失败: " . $result['message'];
    }
    exit;}// 处理下载if (isset($_GET['download'])) {
    $result = $fileHandler->download($_GET['download']);
    if (!$result['success']) {
        echo $result['message'];
    }
    exit;}// 显示文件列表$files = $fileHandler->listFiles();?><!DOCTYPE html><html><head>
    <title>文件上传与下载</title></head><body>
    <h2>文件上传</h2>
    <form method="post" enctype="multipart/form-data">
        <input type="file" name="fileToUpload">
        <button type="submit">上传</button>
    </form>
    
    <h2>文件列表</h2>
    <ul>
        <?php foreach ($files as $file): ?>
            <li>
                <?php echo htmlspecialchars($file); ?>
                <a href="?download=<?php echo urlencode($file); ?>">下载</a>
            </li>
        <?php endforeach; ?>
    </ul></body></html>

总结

这个完整的PHP文件上传下载实现包含以下特点:

  1. 文件上传功能

    • 支持多种文件类型

    • 文件大小限制

    • 防止文件名注入

    • 生成随机文件名增强安全性

  2. 文件下载功能

    • 安全的文件路径检查

    • 正确的Content-Type设置

    • 防止目录遍历攻击

  3. 封装类版本

    • 面向对象设计

    • 可配置的文件类型和大小限制

    • 统一的错误处理

    • 文件列表功能

  4. 安全措施

    • 文件类型检查

    • 文件内容验证(对图片)

    • 安全的文件名处理

    • 防止目录遍历

您可以根据实际需求调整配置参数,或者扩展类的功能。这个实现适合大多数Web应用的文件上传下载需求。



本文关键词: PHP 实现 文件 上传下载 实例

希望以上内容对你有所帮助!如果还有其他问题,请随时提问。 各类知识收集 拥有多年CMS企业建站经验,对 iCMS, LeCMS, ClassCMS, Fastadmin, PbootCMS, PHPCMS, 易优CMS, YzmCMS, 讯睿CMS, 极致CMS, Wordpress, HkCMS, YznCMS, WellCMS, ThinkCMF, 等各类cms的相互转化,程序开发,网站制作,bug修复,程序杀毒,插件定制都可以提供最佳解决方案。

相关推荐

扫码关注

qrcode

QQ交谈

回顶部