$_SERVER["CONTENT_LENGTH"] 使用 XmlHttpRequest 上传文件时返回零

Posted

技术标签:

【中文标题】$_SERVER["CONTENT_LENGTH"] 使用 XmlHttpRequest 上传文件时返回零【英文标题】:$_SERVER["CONTENT_LENGTH"] returning zero when uploading a file using XmlHttpRequest 【发布时间】:2011-04-09 12:49:28 【问题描述】:

我在我的开发机器上遇到了一个问题,它似乎与这台机器隔离,我无法解决。 我有一个 jQuery 文件上传器,它将用户选择的文件发布到 php 脚本中,以便使用 XmlHttpRequest 进行处理。该脚本在我的运行 OSX10.6.3 和 MAMP 1.9 的 MacBook Pro 上运行良好,但是在我的 iMac 上,具有完全相同的操作系统和 MAMP 版本,具有相同的服务器映像,它会失败。

我已经将错误的原因追溯到属性$_SERVER["CONTENT_LENGTH"]return0,即使我可以很好地获取文件名,并且其他所有请求似乎都已成功。出于某种原因,它似乎不会给我实际的内容长度。这是导致问题的代码 - 有问题的函数是 getSize()

class qqUploadedFileXhr 
    /**
     * Save the file to the specified path
     * @return boolean TRUE on success
     */
    function save($path)     
        $input = fopen("php://input", "r");
        $temp = tmpfile();
        $realSize = stream_copy_to_stream($input, $temp);
        fclose($input);

        if ($realSize != $this->getSize())            
            return false;
        

        $target = fopen($path, "w");        
        fseek($temp, 0, SEEK_SET);
        stream_copy_to_stream($temp, $target);
        fclose($target);

        return true;
    
    function getName() 
        return $_GET['qqfile'];
    
    function getSize() 
        if (isset($_SERVER["CONTENT_LENGTH"]))
            return (int)$_SERVER["CONTENT_LENGTH"]; //*THIS* is returning 0            
         else 
            throw new Exception('Getting content length is not supported.');
              
       

【问题讨论】:

还有什么遗漏吗?您是否尝试过 print_r($_SERVER) 和 print_r($_POST) 来查看脚本正在接收的所有字段? print_r'ing 这给了我大量的字段,包括正确的查询字符串、脚本标题和位置等。有什么我应该特别寻找的吗?由于字符太多,我无法在此处粘贴整个回复。 【参考方案1】:

您是否将编码类型设置为multipart/form-data

<form action="upload.php" method="post" enctype="multipart/form-data">
  ...
  <input type="file" ... />
  ...
</form>

【讨论】:

是的,这是由jQuery插件处理的,编码是正确的。【参考方案2】:

解决了!似乎我使用的 jQuery 脚本在 firefox 3.5.x 下失败了,我更新到 3.6.9 并且工作正常。

现在我必须想办法让它向后兼容旧版本的 Firefox。

【讨论】:

【参考方案3】:

我使用的是同一个插件,即使在旧浏览器上,最新版本似乎也能正常工作。我仍然有一些 IE6 和 IE7 的显示/渲染问题,但我通过使按钮不透明并添加图像来覆盖它解决了这些问题。我还将接收 PHP 脚本修改为一个函数而不是多个函数。不适合所有场合,但它适用于所有浏览器:

public function web_upload_file_ajax()
    $return             = array();
    $uploaded_file      = array('name'=>'', 'size'=>0);
    // list of valid extensions, ex. array("jpeg", "xml", "bmp")
    $allowedExtensions  = array('jpg', 'jpeg', 'png', 'gif', 'bmp','txt','csv');
    // max file size in bytes
    $sizeLimit          = 3 * 1024 * 1024;
    //folder to upload the file to - add slash at end
    $uploadDirectory    = TMPPATH.'tmp_upload'.DIRECTORY_SEPARATOR;
    if(!is_dir($uploadDirectory))
        @mkdir($uploadDirectory, 0766, true);
    
    if(!is_dir($uploadDirectory))
        $return         = array('error' => 'Server error. Impossible to create the cache folder:'.$uploadDirectory);
    elseif(!is_writable($uploadDirectory))
        $return         = array('error' => 'Server error. Upload directory is not writable.');
     else 
        $postSize           = $this->bytes_to_num(ini_get('post_max_size'));
        $uploadSize         = $this->bytes_to_num(ini_get('upload_max_filesize'));

        if ($postSize < $sizeLimit || $uploadSize < $sizeLimit)
            $size = max(1, $sizeLimit / 1024 / 1024) . 'M';
            $return = array('error' => 'increase post_max_size and upload_max_filesize to '.$size);
        elseif (isset($_GET['qqfile'])) 
            $uploaded_file['name']  = $_GET['qqfile'];
            if (isset($_SERVER['CONTENT_LENGTH']))
                $uploaded_file['size']  = (int)$_SERVER['CONTENT_LENGTH'];
             else 
                $return = array('error'=>'Getting content length is not supported.');
            
         elseif (isset($_FILES['qqfile'])) 
            $uploaded_file['name']  = $_FILES['qqfile']['name'];
            $uploaded_file['size']  = $_FILES['qqfile']['size'];
         else 
            $return = array('error' => 'No files were uploaded.');
        
        if(count($return)==0)
            if($uploaded_file['size'] == 0)                         $return = array('error' => 'File is empty');
            elseif($uploaded_file['size'] > $sizeLimit)             $return = array('error' => 'File is too large');
            elseif($uploaded_file['name']!='')
                $pathinfo   = pathinfo($uploaded_file['name']);
                $filename   = $pathinfo['filename'];
                $ext        = $pathinfo['extension'];
                if($allowedExtensions && !in_array(strtolower($ext), $allowedExtensions))
                    $return = array('error' => 'File has an invalid extension, it should be one of '.implode(', ', $allowedExtensions).'.');
                
            
        
        if(count($return)==0)
            // overwrite previous files that were uploaded
            $filename = ll('sessions')->get_id();

            // don't overwrite previous files that were uploaded
            while (file_exists($uploadDirectory.$filename.'.'.$ext)) 
                $filename .= rand(10, 99);
            

            $saved  = false;
            $path   = $uploadDirectory.$filename.'.'.$ext;
            if (isset($_GET['qqfile'])) 
                $input      = fopen('php://input', 'r');
                $temp       = tmpfile();
                $realSize   = stream_copy_to_stream($input, $temp);
                fclose($input);

                if ($realSize != $uploaded_file['size'])
                    $saved = false;
                 else 
                    $target = fopen($path, 'w');
                    fseek($temp, 0, SEEK_SET);
                    stream_copy_to_stream($temp, $target);
                    fclose($target);
                    $saved = true;
                
             else 
                if(!move_uploaded_file($_FILES['qqfile']['tmp_name'], $path))
                    $saved = false;
                
                $saved = true;
            
            if ($saved)
                $return = array('success'=>true, 'file'=>$filename.'.'.$ext);
             else 
                $return = array('error'=> 'Could not save uploaded file. The upload was cancelled, or server error encountered');
            
        
    
    // to pass data through iframe you will need to encode all html tags
    echo htmlspecialchars(json_encode($return), ENT_NOQUOTES);

这里是我用作辅助函数的 bytes_to_num,但如果你愿意,你也可以将它包含在同一个函数中:

/**
 * This function transforms bytes (like in the the php.ini notation) for numbers (like '2M') to an integer (2*1024*1024 in this case)
 */
public function bytes_to_num($bytes)
    $bytes  = trim($bytes);
    $ret    = $bytes+0;
    if($ret==0 || strlen($ret)>=strlen($bytes))
        return $ret;
    
    $type   = substr($bytes, strlen($ret));
    switch(strtoupper($type))
        case 'P':
        case 'Pb':
            $ret *= 1024;
        case 'T':
        case 'Tb':
            $ret *= 1024;
        case 'G':
        case 'Gb':
            $ret *= 1024;
        case 'M':
        case 'Mb':
            $ret *= 1024;
        case 'K':
        case 'Kb':
            $ret *= 1024;
            break;
    
    return $ret;

【讨论】:

【参考方案4】:
$headers = apache_request_headers();
echo $headers['Content-Length'];

我假设这个也返回 0?

【讨论】:

【参考方案5】:

可能正在使用分块编码,它不会发送内容长度。

【讨论】:

以上是关于$_SERVER["CONTENT_LENGTH"] 使用 XmlHttpRequest 上传文件时返回零的主要内容,如果未能解决你的问题,请参考以下文章

$_SERVER["CONTENT_LENGTH"] 使用 XmlHttpRequest 上传文件时返回零

带有多个“server_name”条目的 nginx“server”指令:始终将第一个传递给 PHP 的 $_SERVER['SERVER_NAME']

如何利用$_SERVER["PHP_SELF"]变量植入script代码?

PHP中为啥我获取不到$_SERVER["REMOTE_USER"]的值?

URL操作

][SQL Server]关键字 'like' 附近有语法错误。