【问题标题】:Can't upload 5mb file using AJAX file uploader无法使用 AJAX 文件上传器上传 5mb 文件
【发布时间】:2011-11-22 00:09:54
【问题描述】:

我正在使用文件上传插件(来自:https://github.com/valums/file-uploader)将文件上传到我的网站。

如果您使用的是现代网络浏览器(如 Firefox 6 或 Chrome 13),则它会通过在 POST 正文中流式传输文件来上传,并且可以为您提供进度条。如果您使用的是 IE(或旧版浏览器),它会使用标准的 $_FILES(使用隐藏的 iFrame)。

一切正常,但突然我无法在 Chrome 或 Firefox 中上传 5MB 的文件。当我在 Chome 或 Firefox 中上传一个 5MB 的文件时,我收到 500 错误,我的 PHP 代码甚至从未运行过。如果我使用 Internet Explorer(它使用 $_FILES),它可以正常工作。

这一定是配置问题,因为我的 PHP 代码甚至从未运行过。所以,我检查了我的设置。

/etc/php.ini

upload_max_filesize = 15M
post_max_size = 16M

我找了LimitRequestBody,但是找不到(默认是无限的)。

设置看起来不错。我调试了一段时间,我不知道是什么问题。

有没有我缺少的设置?服务器已经安装了 suhosin,如果这很重要的话。

这是我正在使用的后端(我正在使用 CodeIgniter)代码。

// Can we use the fancy file uploader?
if($this->input->get('qqfile') !== FALSE){ // Yes we can :-)
    $name = preg_replace('/[^\-\(\)\d\w\.]/','_', $this->input->get('qqfile'));
    // Upload the file using black magic :-)
    $input = fopen("php://input", 'r');
    $temp = tmpfile();
    $fileSize = stream_copy_to_stream($input, $temp);
    fclose($input);
    if($fileSize > 15728640){
        $ret['error'] = 'File not uploaded: file cannot be larger than 15 MB';
    }               
    elseif(isset($_SERVER['CONTENT_LENGTH']) && $fileSize === (int)$_SERVER['CONTENT_LENGTH']){
        $path = $folder.'/'.$name; // Where to put the file
        // Put the temp uploaded file into the correct spot
        $target = fopen($path, 'w');
        fseek($temp, 0, SEEK_SET);
        stream_copy_to_stream($temp, $target);
        fclose($target);
        fclose($temp);

        $ret['fileSize'] = $fileSize;
        $ret['success'] = true;
    }
    else{
        $ret['error'] = 'File not uploaded: content length error';
    }
}
else{ // IE 6-8 can't use the fancy uploader, so use the standard $_FILES
    $file = $_FILES['qqfile'];
    $file['name'] = preg_replace('/[^\-\(\)\d\w\.]/','_', $file['name']);
    $config['file_name'] = $file['name'];
    // Upload the file using CodeIgniter's upload class (using $_FILES)
    $_FILES['userfile'] = $_FILES['qqfile'];
    unset($_FILES['qqfile']);
    $config['upload_path'] = $folder;
    $config['allowed_types'] = '*';
    $config['max_size'] = 15360; //15 MB
    $this->load->library('upload', $config);
    if($this->upload->do_upload()){ // Upload was successful :-)
        $upload = $this->upload->data();
        $ret['success'] = true;
        $ret['fileSize'] = $upload['fileSize']/1000;
    }
    else{ // Upload was NOT successful
        $ret['error'] = 'File not uploaded: '.$this->upload->display_errors('', '');
        $ret['type'] = $_FILES['userfile']['type'];
    }
    echo json_encode($ret);
}

我知道我的代码可以正常工作,因为小于 4MB 的文件可以正常上传(在所有浏览器上)。我只对大于 5mb 的文件有问题(使用 Chrome/Firefox)。奇怪的是,这在我的测试服务器上运行良好,但不是我的生产服务器。它们可能有不同的设置(suhosin 正在生产中,但未在测试中)。

【问题讨论】:

  • 为澄清起见:根据您的最后一段“在产品服务器上小于 5MB 的文件无法在 IE 上上传,在测试服务器上所有大小的文件都可以正常上传”?
  • @AshwiniDhekane:在我的 prod 服务器上,如果我使用 Chrome,我只能上传 4mb 或更小的文件。如果我在我的产品服务器上使用 IE 5mb 和更大的文件可以工作。在我的测试服务器上,所有浏览器都可以正常运行。
  • 我在 ServerFault (serverfault.com/questions/313961/…) 上重新询问了这个问题,发现 stream_copy_to_stream 可能使用了太多 RAM。提高 memory_limit 暂时修复它,但如果像 100 个用户每个尝试上传 15MB 文件,我可能会用完 RAM。
  • 哇!!结果确实是服务器问题。了解浏览器是如何导致这种不稳定行为的将会很有趣......
  • @AshwiniDhekane:这是因为 Internet Explorer 使用普通的 $_FILES 方法上传文件。现代浏览器(Chrome/Firefox)使用该插件通过 XHR 上传文件(通过在 POST 正文中流式传输文件)。 $_FILES 没有使用 stream_copy_to_stream,所以效果很好。

标签: php ajax apache codeigniter suhosin


【解决方案1】:

请通过查看<?php phpinfo(); ?>检查您的php.ini设置是否正确加载。

【讨论】:

  • upload_max_filesize 是 15MB,post_max_size 在 ini 文件和 phpinfo(); 中是 16MB。是否有其他设置可能是问题?
  • 有时您的网络服务器也可能具有最大 POST 大小。
【解决方案2】:

我查看了我的 apache 日志,发现

PHP 致命错误:16777216 字节的允许内存大小已用尽(尝试分配 5242881 字节)

我把memory_limit改成了64M,现在好像可以了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-16
    • 2018-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    相关资源
    最近更新 更多