Skip to content

18.5 上传失败

问题描述

在 PHP 开发中,文件上传失败是一个常见的问题。当用户尝试上传文件时,可能会遇到各种错误,如文件过大、类型不允许、上传路径不存在等。

常见原因

1. 文件大小超过限制

上传的文件大小超过了 PHP 或服务器的限制。

示例

php
<?php
// 上传文件
if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
    if ($file['error'] == UPLOAD_ERR_INI_SIZE) {
        echo '文件大小超过了 php.ini 中的限制';
    }
}
?>

2. 文件类型不允许

上传的文件类型不在允许的范围内。

示例

php
<?php
// 检查文件类型
$allowed_types = array('jpg', 'jpeg', 'png', 'gif');
$file_ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);

if (!in_array(strtolower($file_ext), $allowed_types)) {
    echo '不允许的文件类型';
}
?>

3. 上传路径不存在或无权限

上传路径不存在或 PHP 脚本没有写入权限。

示例

php
<?php
// 上传文件
$upload_dir = 'uploads/';

if (!is_dir($upload_dir)) {
    echo '上传目录不存在';
}

if (!is_writable($upload_dir)) {
    echo '上传目录无写入权限';
}
?>

4. 临时文件夹问题

临时文件夹不存在或无权限。

5. 网络问题

网络连接中断或超时导致上传失败。

6. 文件名重复

上传的文件名与服务器上已有的文件名重复。

排查方法

1. 检查文件大小限制

检查 PHP 配置中的文件大小限制:

php
<?php
echo '上传文件大小限制: ' . ini_get('upload_max_filesize') . '<br>';
echo 'POST 数据大小限制: ' . ini_get('post_max_size') . '<br>';
?>

2. 检查文件类型

检查上传的文件类型是否在允许的范围内:

php
<?php
if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
    echo '文件类型: ' . $file['type'] . '<br>';
    echo '文件扩展名: ' . pathinfo($file['name'], PATHINFO_EXTENSION) . '<br>';
}
?>

3. 检查上传路径

检查上传路径是否存在且有写入权限:

php
<?php
$upload_dir = 'uploads/';
echo '上传目录是否存在: ' . (is_dir($upload_dir) ? '是' : '否') . '<br>';
echo '上传目录是否可写: ' . (is_writable($upload_dir) ? '是' : '否') . '<br>';
?>

4. 检查临时文件夹

检查临时文件夹是否存在且有写入权限:

php
<?php
echo '临时文件夹: ' . sys_get_temp_dir() . '<br>';
echo '临时文件夹是否可写: ' . (is_writable(sys_get_temp_dir()) ? '是' : '否') . '<br>';
?>

5. 检查上传错误

检查上传过程中是否有错误:

php
<?php
if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
    echo '上传错误代码: ' . $file['error'] . '<br>';
    
    switch ($file['error']) {
        case UPLOAD_ERR_OK:
            echo '上传成功';
            break;
        case UPLOAD_ERR_INI_SIZE:
            echo '文件大小超过了 php.ini 中的限制';
            break;
        case UPLOAD_ERR_FORM_SIZE:
            echo '文件大小超过了表单中的限制';
            break;
        case UPLOAD_ERR_PARTIAL:
            echo '文件只上传了一部分';
            break;
        case UPLOAD_ERR_NO_FILE:
            echo '没有上传文件';
            break;
        case UPLOAD_ERR_NO_TMP_DIR:
            echo '临时文件夹不存在';
            break;
        case UPLOAD_ERR_CANT_WRITE:
            echo '无法写入临时文件';
            break;
        case UPLOAD_ERR_EXTENSION:
            echo '文件上传被扩展阻止';
            break;
        default:
            echo '未知错误';
            break;
    }
}
?>

解决方案

1. 增加文件大小限制

修改 php.ini 文件,增加文件大小限制:

ini
; php.ini
upload_max_filesize = 8M
post_max_size = 16M

2. 允许更多文件类型

修改代码,允许更多文件类型:

php
<?php
// 允许的文件类型
$allowed_types = array('jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx');
$file_ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);

if (in_array(strtolower($file_ext), $allowed_types)) {
    // 上传文件
} else {
    echo '不允许的文件类型';
}
?>

3. 创建上传目录并设置权限

创建上传目录并设置正确的权限:

php
<?php
$upload_dir = 'uploads/';

// 创建上传目录
if (!is_dir($upload_dir)) {
    mkdir($upload_dir, 0777, true);
}

// 设置权限
chmod($upload_dir, 0777);
?>

4. 处理文件名重复

使用唯一文件名避免文件名重复:

php
<?php
$upload_dir = 'uploads/';
$file_name = $_FILES['file']['name'];
$file_ext = pathinfo($file_name, PATHINFO_EXTENSION);
$unique_name = uniqid() . '.' . $file_ext;
$file_path = $upload_dir . $unique_name;

// 移动上传文件
if (move_uploaded_file($_FILES['file']['tmp_name'], $file_path)) {
    echo '上传成功';
} else {
    echo '上传失败';
}
?>

5. 优化上传表单

优化上传表单,添加文件大小限制和文件类型提示:

html
<!-- 优化上传表单 -->
<form method="post" action="upload.php" enctype="multipart/form-data">
    <input type="file" name="file" accept=".jpg,.jpeg,.png,.gif">
    <p>允许的文件类型:JPG, JPEG, PNG, GIF</p>
    <p>文件大小限制:8MB</p>
    <input type="submit" value="上传">
</form>

6. 使用分块上传

对于大文件,使用分块上传:

php
<?php
// 分块上传处理
if (isset($_POST['chunk']) && isset($_POST['chunks'])) {
    $chunk = intval($_POST['chunk']);
    $chunks = intval($_POST['chunks']);
    $file_name = $_POST['name'];
    $upload_dir = 'uploads/';
    $file_path = $upload_dir . $file_name;
    
    // 打开文件
    $handle = fopen($file_path, $chunk == 0 ? 'w' : 'a');
    if ($handle) {
        // 读取上传的块
        $data = file_get_contents('php://input');
        // 写入文件
        fwrite($handle, $data);
        fclose($handle);
        
        // 检查是否所有块都已上传
        if ($chunk == $chunks - 1) {
            echo '上传成功';
        } else {
            echo '块上传成功';
        }
    } else {
        echo '无法打开文件';
    }
}
?>

实战演练

场景:文件上传失败

问题:用户上传文件时失败,错误信息为 文件大小超过了 php.ini 中的限制

排查步骤

  1. 检查文件大小限制:查看 php.ini 中的 upload_max_filesizepost_max_size 设置。
  2. 检查上传文件大小:确认上传的文件大小是否超过了限制。
  3. 修改配置:修改 php.ini 文件,增加文件大小限制。

解决方案

  1. 修改 php.ini 文件

    ini
    ; php.ini
    upload_max_filesize = 16M
    post_max_size = 24M
  2. 重启服务器

    bash
    sudo service apache2 restart
  3. 验证设置

    php
    <?php
    echo '上传文件大小限制: ' . ini_get('upload_max_filesize') . '<br>';
    echo 'POST 数据大小限制: ' . ini_get('post_max_size') . '<br>';
    ?>

场景:上传目录无权限

问题:用户上传文件时失败,错误信息为 无法写入文件

排查步骤

  1. 检查上传目录:确认上传目录是否存在。
  2. 检查权限:确认上传目录是否有写入权限。
  3. 设置权限:为上传目录设置正确的权限。

解决方案

  1. 创建上传目录

    php
    <?php
    $upload_dir = 'uploads/';
    if (!is_dir($upload_dir)) {
        mkdir($upload_dir, 0777, true);
    }
    ?>
  2. 设置权限

    bash
    chmod -R 777 uploads/
  3. 验证权限

    php
    <?php
    $upload_dir = 'uploads/';
    echo '上传目录是否存在: ' . (is_dir($upload_dir) ? '是' : '否') . '<br>';
    echo '上传目录是否可写: ' . (is_writable($upload_dir) ? '是' : '否') . '<br>';
    ?>

总结

文件上传失败是 PHP 开发中常见的问题,通常由文件大小超过限制、文件类型不允许、上传路径不存在或无权限、临时文件夹问题、网络问题或文件名重复导致。通过检查文件大小限制、文件类型、上传路径、临时文件夹和上传错误,可以有效地排查和解决这些问题。

在开发过程中,应该注意以下几点:

  • 合理设置文件大小限制
  • 明确允许的文件类型
  • 确保上传目录存在且有写入权限
  • 处理文件名重复问题
  • 优化上传表单,添加文件大小限制和文件类型提示
  • 对于大文件,使用分块上传

通过这些措施,可以减少文件上传失败的发生,提高应用程序的用户体验。

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