Skip to content

第 13 章:文件上传与图片处理

13.1 文件上传表单

基本表单结构

文件上传表单需要设置 enctype="multipart/form-data" 属性,否则无法上传文件。

html
<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="上传文件" name="submit">
</form>

多文件上传

html
<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="files[]" multiple>
    <input type="submit" value="上传文件" name="submit">
</form>

13.2 $_FILES 获取上传信息

$_FILES 数组结构

当文件上传时,PHP 会将上传文件的信息存储在 $_FILES 超级全局数组中。

单文件上传时的 $_FILES 结构

php
Array(
    [fileToUpload] => Array(
        [name] => example.jpg      // 原始文件名
        [type] => image/jpeg       // 文件类型
        [tmp_name] => /tmp/phpXXXXXX  // 临时文件路径
        [error] => 0               // 错误码(0 表示成功)
        [size] => 102400           // 文件大小(字节)
    )
)

多文件上传时的 $_FILES 结构

php
Array(
    [files] => Array(
        [name] => Array(
            [0] => file1.jpg
            [1] => file2.png
        )
        [type] => Array(
            [0] => image/jpeg
            [1] => image/png
        )
        [tmp_name] => Array(
            [0] => /tmp/phpXXXXXX
            [1] => /tmp/phpYYYYYY
        )
        [error] => Array(
            [0] => 0
            [1] => 0
        )
        [size] => Array(
            [0] => 102400
            [1] => 204800
        )
    )
)

13.3 上传验证(大小、类型、重命名)

错误码说明

错误码描述
0上传成功
1文件大小超过 php.ini 中的 upload_max_filesize 设置
2文件大小超过表单中的 MAX_FILE_SIZE 设置
3文件只上传了一部分
4没有文件被上传
6缺少临时文件夹
7文件写入失败

上传验证示例

php
<?php
if (isset($_POST["submit"])) {
    $target_dir = "uploads/";
    $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
    $uploadOk = 1;
    $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
    
    // 检查文件是否是图片
    if(isset($_POST["submit"])) {
        $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
        if($check !== false) {
            echo "文件是图片 - " . $check["mime"] . ".";
            $uploadOk = 1;
        } else {
            echo "文件不是图片.";
            $uploadOk = 0;
        }
    }
    
    // 检查文件是否已存在
    if (file_exists($target_file)) {
        echo "抱歉,文件已存在.";
        $uploadOk = 0;
    }
    
    // 检查文件大小
    if ($_FILES["fileToUpload"]["size"] > 500000) {
        echo "抱歉,您的文件太大.";
        $uploadOk = 0;
    }
    
    // 允许的文件格式
    if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
    && $imageFileType != "gif" ) {
        echo "抱歉,只允许 JPG, JPEG, PNG 和 GIF 文件.";
        $uploadOk = 0;
    }
    
    // 检查 $uploadOk 是否为 0
    if ($uploadOk == 0) {
        echo "抱歉,您的文件未上传.";
    // 尝试上传文件
    } else {
        if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
            echo "文件 ". htmlspecialchars( basename( $_FILES["fileToUpload"]["name"])). " 已成功上传.";
        } else {
            echo "抱歉,上传文件时出错.";
        }
    }
}
?>

文件重命名

为了避免文件名冲突,通常会对上传的文件进行重命名。

php
<?php
$target_dir = "uploads/";
$filename = basename($_FILES["fileToUpload"]["name"]);
$extension = pathinfo($filename, PATHINFO_EXTENSION);
$new_filename = uniqid() . "." . $extension;
$target_file = $target_dir . $new_filename;

// 上传文件
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "文件已成功上传,新文件名: " . $new_filename;
}
?>

13.4 头像上传、图片展示

头像上传示例

php
<?php
session_start();

// 检查是否登录
if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}

$message = '';
$message_type = '';

if (isset($_POST['upload_avatar'])) {
    // 检查是否有文件上传
    if (!isset($_FILES['avatar']) || $_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
        $message = '请选择要上传的文件';
        $message_type = 'error';
    } else {
        // 设置上传目录
        $upload_dir = 'uploads/avatars/';
        
        // 确保目录存在
        if (!file_exists($upload_dir)) {
            mkdir($upload_dir, 0777, true);
        }
        
        // 获取文件信息
        $file = $_FILES['avatar'];
        $filename = basename($file['name']);
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        
        // 验证文件类型
        $allowed_types = ['jpg', 'jpeg', 'png', 'gif'];
        if (!in_array($extension, $allowed_types)) {
            $message = '只允许上传 JPG、JPEG、PNG 和 GIF 格式的图片';
            $message_type = 'error';
        } else {
            // 生成唯一文件名
            $new_filename = $_SESSION['user_id'] . '.' . $extension;
            $target_file = $upload_dir . $new_filename;
            
            // 上传文件
            if (move_uploaded_file($file['tmp_name'], $target_file)) {
                // 更新用户头像路径到数据库
                // 这里应该有数据库更新代码
                
                $message = '头像上传成功';
                $message_type = 'success';
                
                // 更新 session 中的头像路径
                $_SESSION['avatar'] = $target_file;
            } else {
                $message = '上传失败,请重试';
                $message_type = 'error';
            }
        }
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>上传头像</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .container {
            width: 400px;
            margin: 0 auto;
        }
        .avatar-preview {
            width: 150px;
            height: 150px;
            border-radius: 50%;
            overflow: hidden;
            margin: 20px 0;
        }
        .avatar-preview img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
        input[type="file"] {
            margin: 10px 0;
        }
        button {
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        .success {
            color: green;
        }
        .error {
            color: red;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>上传头像</h1>
        
        <!-- 显示消息 -->
        <?php if (!empty($message)): ?>
            <p class="<?php echo $message_type; ?>"><?php echo $message; ?></p>
        <?php endif; ?>
        
        <!-- 头像预览 -->
        <div class="avatar-preview">
            <?php if (isset($_SESSION['avatar']) && file_exists($_SESSION['avatar'])): ?>
                <img src="<?php echo $_SESSION['avatar']; ?>" alt="头像">
            <?php else: ?>
                <img src="https://via.placeholder.com/150" alt="默认头像">
            <?php endif; ?>
        </div>
        
        <!-- 上传表单 -->
        <form method="post" enctype="multipart/form-data">
            <input type="file" name="avatar" accept="image/*" required>
            <br>
            <button type="submit" name="upload_avatar">上传头像</button>
        </form>
        
        <p><a href="profile.php">返回个人资料</a></p>
    </div>
</body>
</html>

图片展示

php
<?php
// 显示上传的图片
$upload_dir = 'uploads/';
$files = scandir($upload_dir);

echo '<h2>上传的图片</h2>';
echo '<div style="display: flex; flex-wrap: wrap;">';

foreach ($files as $file) {
    if ($file != '.' && $file != '..') {
        $file_path = $upload_dir . $file;
        $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        
        // 只显示图片文件
        if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) {
            echo '<div style="margin: 10px;">';
            echo '<img src="' . $file_path . '" style="width: 150px; height: 150px; object-fit: cover;">';
            echo '<p>' . $file . '</p>';
            echo '</div>';
        }
    }
}

echo '</div>';
?>

13.5 实操:用户头像上传

创建 upload-avatar.php 文件

php
<?php
session_start();

// 模拟用户登录
if (!isset($_SESSION['user_id'])) {
    $_SESSION['user_id'] = 1;
    $_SESSION['username'] = '张三';
}

$message = '';
$message_type = '';

if (isset($_POST['upload_avatar'])) {
    // 检查是否有文件上传
    if (!isset($_FILES['avatar']) || $_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
        $message = '请选择要上传的文件';
        $message_type = 'error';
    } else {
        // 设置上传目录
        $upload_dir = 'uploads/avatars/';
        
        // 确保目录存在
        if (!file_exists($upload_dir)) {
            mkdir($upload_dir, 0777, true);
        }
        
        // 获取文件信息
        $file = $_FILES['avatar'];
        $filename = basename($file['name']);
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        
        // 验证文件类型
        $allowed_types = ['jpg', 'jpeg', 'png', 'gif'];
        if (!in_array($extension, $allowed_types)) {
            $message = '只允许上传 JPG、JPEG、PNG 和 GIF 格式的图片';
            $message_type = 'error';
        } else {
            // 生成唯一文件名
            $new_filename = $_SESSION['user_id'] . '.' . $extension;
            $target_file = $upload_dir . $new_filename;
            
            // 上传文件
            if (move_uploaded_file($file['tmp_name'], $target_file)) {
                $message = '头像上传成功';
                $message_type = 'success';
                
                // 更新 session 中的头像路径
                $_SESSION['avatar'] = $target_file;
            } else {
                $message = '上传失败,请重试';
                $message_type = 'error';
            }
        }
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>用户头像上传</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .container {
            width: 400px;
            margin: 0 auto;
            padding: 20px;
            border: 1px solid #ccc;
            border-radius: 5px;
            background-color: #f9f9f9;
        }
        .avatar-preview {
            width: 150px;
            height: 150px;
            border-radius: 50%;
            overflow: hidden;
            margin: 20px auto;
            border: 2px solid #ddd;
        }
        .avatar-preview img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
        input[type="file"] {
            margin: 10px 0;
            width: 100%;
        }
        button {
            width: 100%;
            padding: 10px;
            margin: 10px 0;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        .success {
            color: green;
            text-align: center;
        }
        .error {
            color: red;
            text-align: center;
        }
        h1 {
            text-align: center;
            color: #333;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>用户头像上传</h1>
        
        <!-- 显示消息 -->
        <?php if (!empty($message)): ?>
            <p class="<?php echo $message_type; ?>"><?php echo $message; ?></p>
        <?php endif; ?>
        
        <!-- 头像预览 -->
        <div class="avatar-preview">
            <?php if (isset($_SESSION['avatar']) && file_exists($_SESSION['avatar'])): ?>
                <img src="<?php echo $_SESSION['avatar']; ?>" alt="头像">
            <?php else: ?>
                <img src="https://via.placeholder.com/150" alt="默认头像">
            <?php endif; ?>
        </div>
        
        <!-- 上传表单 -->
        <form method="post" enctype="multipart/form-data">
            <input type="file" name="avatar" accept="image/*" required>
            <button type="submit" name="upload_avatar">上传头像</button>
        </form>
        
        <p style="text-align: center;"><a href="#">返回个人中心</a></p>
    </div>
</body>
</html>

访问页面

  1. 将文件保存到网站根目录
  2. 确保 uploads/avatars/ 目录存在且有写入权限
  3. 打开浏览器,访问 http://localhost/upload-avatar.php
  4. 测试头像上传功能

小结

通过本章的学习,你掌握了 PHP 文件上传的基本方法,包括创建文件上传表单、获取上传文件信息、验证文件、重命名文件以及处理图片上传。这些知识在开发用户头像上传、文件管理等功能时非常重要。在后续的实战项目中,你将使用这些技术来实现文件上传和图片处理功能。

© 2026 编程马·菜鸟教程 版权所有