$ _SERVER ["CONTENT_LENGTH"] возвращает ноль при загрузке файла с использованием XmlHttpRequest - PullRequest
9 голосов
/ 08 сентября 2010

У меня проблема с моей машиной для разработки, которая кажется изолированной от этой машины, и я не могу ее решить. У меня есть загрузчик файлов jQuery, который отправляет выбранный пользователем файл в сценарий PHP для обработки с использованием XmlHttpRequest. Сценарий отлично работает на моем MacBook Pro, работающем под управлением OSX10.6.3 с MAMP 1.9, однако на моем iMac с точно такой же операционной системой и версией MAMP, с идентичным образом сервера, происходит сбой.

Я отследил причину ошибки до свойства $_SERVER["CONTENT_LENGTH"], возвращающего 0, хотя я могу получить имя файла просто отлично, и все остальное, похоже, успешно выполнено в запросе. По какой-то причине это просто не дает мне фактическую длину контента. Вот код, который вызывает проблему - рассматриваемая функция 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.');
        }      
    }   
}

Ответы [ 5 ]

6 голосов
/ 08 сентября 2010

Решено! Кажется, что скрипт jQuery, который я использую, терпит неудачу в Firefox 3.5.x, я обновил до 3.6.9, и он работает нормально.

Теперь мне нужно найти способ сделать его обратно совместимым со старыми версиями Firefox.

3 голосов
/ 09 ноября 2011

Возможно, используется чанкованное кодирование, которое не будет отправлять длину контента.

3 голосов
/ 08 сентября 2010

Вы установили тип кодировки на multipart/form-data?

<form action="upload.php" method="post" enctype="multipart/form-data">
  ...
  <input type="file" ... />
  ...
</form>
0 голосов
/ 08 ноября 2011
$headers = apache_request_headers();
echo $headers['Content-Length'];

Я предполагаю, что этот также возвращает 0?

0 голосов
/ 07 ноября 2011

Я использую тот же плагин, последняя версия, кажется, работает нормально даже со старыми браузерами.У меня все еще есть проблемы с отображением / рендерингом в 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...