duanpin2009 2015-06-03 13:40
浏览 75

HTML5 PHP文件上传器无法在iOS 8 Safari上运行

I have been working on a browser based file uploader that sends files to our S3 buckets for the past couple of months. I've made great progress in the last couple of weeks. However, my biggest road block came in the form of iDevices. Pretty much anything that runs on iOS 8 has been giving me major headaches relating to my uploader. I am able to run my program on Chrome, Firefox, and Safari on desktops/laptops on both PC and MAC. However, when it comes to mobile devices, only Android devices work the intended way. On iOS, Chrome only uploads small files and anything large will return a file that has a size of 0. Safari out right fails. I know that there have been issues with iOS 8 relating to this issue, but from my research, this issue should have been taken care of already. Anyways, I was wondering if there was a work around this problem so that I can upload my files like I am doing for the other devices and browsers.

Error uploading a small image file:

Syntax: JSON Parse error: Unexpected EOF

Failed to load resource: request body stream exhausted

Error uploading a big video file:

Failed to load resource: request body stream exhausted

SyntaxError: JSON Parse error: Unrecognized token '<'

If you would like to see any examples of my code, feel free to ask as I will edit my post for this request.

upload.js

    var files;                      // Array of inputed files
    var ownerName;                  // Inputed name of file owner
    var totalSize = 0;              // Total file size of all files
    var loaded    = 0;              // Loaded data amount
    var MB        = 1024 * 1024;    // 1 MB
    var partSize  = MB;             // Data amount of part of chunk of file 
    var chunkSize = 5 * MB;         // Data amount of chunk of file

    function request(command, xhr, formdata){
        xhr.open("POST", "FileUploader.php", true);
        if(command === 'UploadPart' || command === 'PutObject')
            xhr.upload.addEventListener("progress", progressHandler, false);
        xhr.addEventListener("load", completeHandler, false);
        xhr.addEventListener("error", errorHandler, false);
        xhr.addEventListener("abort", abortHandler, false);
        xhr.send(formdata);
        return xhr;
    }

    function uploadFile(){
        reset();
        if (window.File && window.FileReader && window.FileList && window.Blob){
            files = _("file").files;
            totalSize = calcTotalSize(files);
            for (var i = 0; i < files.length; i++){
                var key = createKey(_("name").value, files[i]);
                if (files[i].size >= chunkSize)
                    createMultipartUpload(i, key);  
                else
                    putObject(i, key);
            }
        }
        else
            alert("Your browser does not support our File Uploader.");
    }

    function createMultipartUpload(i, key){
        var formdata = new FormData();
        formdata.append("command", 'CreateMultipartUpload');
        formdata.append("fileindex", i);
        formdata.append("key", key);
        var xhr = request('CreateMultipartUpload', new XMLHttpRequest(), formdata);
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4)
                uploadPart(JSON.parse(xhr.responseText), 1);
        };
    }

    function uploadPart(sendBackData, partNum){
        console.log("Uploading part " + partNum); 
        var fileIndex = sendBackData['fileindex'];
        var file      = files[fileIndex];

        if (partNum > Math.ceil(file.size / chunkSize)) {
            completeMultipartUpload(sendBackData);
            return;
        }

        var blobs     = [];
        var start     = (partNum - 1) * chunkSize;
        var end       = start + partSize;
        var index     = 0;

        while (start < chunkSize*partNum){
            blobs.push(file.slice(start, end));
            start = end;
            end = start + partSize;
            index++;
        }

        var formdata = new FormData();
        for(var i = 0; i < index; i++)
            formdata.append("file[]", blobs[i]);
        formdata.append("command", 'UploadPart');
        formdata.append("uploadId", sendBackData['uploadId']);
        formdata.append("key", sendBackData['key']);
        formdata.append("partNumber", partNum);

        var xhr = request('UploadPart', new XMLHttpRequest(), formdata);
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4)
                uploadPart(sendBackData, partNum + 1);
        };
    }

    function completeMultipartUpload(sendBackData) {
        var formdata = new FormData();
        formdata.append("command", 'CompleteMultipartUpload');
        formdata.append("uploadId", sendBackData['uploadId']);
        formdata.append("key", sendBackData['key']);

        var xhr = request('CompleteMultipartUpload', new XMLHttpRequest(), formdata);
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                var sendBackData = JSON.parse(xhr.responseText);
                if(sendBackData['success'])
                    displayURL(sendBackData['url']);
            }
        };
    }

FileUploader.php

<?php
    function sendJson($arr)
    {
        header('Content-Type: application/json');
        die(json_encode($arr));
    }

    $s3 = S3Client::factory(array(
        'key'     => AWS_KEY,
        'secret'  => AWS_SECRET_KEY
    ));

    $command = $_POST['command'];
    s3Command($command);

function s3Command($command){
    $key = $_POST['key'];
    switch ($command) {
        case 'CreateMultipartUpload':
            $fileindex = $_POST['fileindex'];

            $response = $GLOBALS["s3"]->createMultipartUpload(array(
                'Bucket'    => TMP_IMG,
                'Key'       => $key,
                'ACL'       => 'public-read',
            ));

            $uploadId = $response['UploadId'];

            sendJson(array(
                'uploadId'  => $uploadId,
                'key'       => $key,
                'fileindex' => $fileindex
            ));
            break;

        case 'UploadPart':
            $tmp_files = $_FILES['file'];
            $files = array();
            for ($i = 0; $i < count($tmp_files['name']); $i++){
                $files[] = array(
                    'name' => $tmp_files['name'][$i],
                    'tmp_name' => $tmp_files['tmp_name'][$i],
                    'type' => $tmp_files['type'][$i],
                    'size' => $tmp_files['size'][$i],
                    'error' => $tmp_files['error'][$i]
                );
            }

            $body = mergeFiles($files);

            $result = $GLOBALS["s3"]->uploadPart(array(
                'Bucket'    => TMP_IMG,
                'Key'       => $key,
                'UploadId'  => $_POST['uploadId'],
                'PartNumber'=> $_POST['partNumber'],
                'Body'      => $body
            ));
            break;

        case 'CompleteMultipartUpload':
            $partsModel = $GLOBALS["s3"]->listParts(array(
                'Bucket' => TMP_IMG,
                'Key'       => $key,
                'UploadId'  => $_POST['uploadId']
            ));

            $model = $GLOBALS["s3"]->completeMultipartUpload(array(
                'Bucket' => TMP_IMG,
                'Key' => $key,
                'UploadId' => $_POST['uploadId'],
                'Parts' => $partsModel['Parts'],
            ));

            $url = $GLOBALS["s3"]->getObjectUrl(TMP_IMG, $key);

            $type = explode('/', $key);

            if($type[0] == 'image'){
                $result = $GLOBALS["s3"]->getObject(array(
                    'Bucket' => TMP_IMG,
                    'Key'    => $key
                ));

                $body = $result['Body'];

                $url = resizeImage($url);
            }

            sendJson(array(
                'success' => true,
                'url'     => $url
            ));
            break;

        case 'AbortMultipartUpload':
            $s3->abortMultipartUpload(array(
                'Bucket'   => TMP_IMG,
                'Key'      => $key,
                'UploadId' => $_POST['uploadId']
            ));
            break;
    }
}
?>
  • 写回答

2条回答 默认 最新

  • dongqie8661 2015-06-04 20:58
    关注

    The error that I should have been focusing on was the:

    Failed to load resource: request body stream exhausted

    I came across this page.

    My issue wasn't with the JSON Parsing but the directory that my scripts were in requiring authentication on our IIS 8 server. iOS has a weird policy when it come to authentication. What I did was moved my script outside the directory and it works as intended.

    评论

报告相同问题?

悬赏问题

  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥30 python代码,帮调试,帮帮忙吧
  • ¥15 #MATLAB仿真#车辆换道路径规划