多个图像上传JavaScript数组Stringify与大图像base64的斗争?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (131)

我正在尝试添加一个多图像上传器,它返回一个由用户选择图像填充的JavaScript数组。我将使用这个图像上传器与其他输入表单元素一起提交,在这种情况下,我不使用AJAX。最大文件上载大小为2MB。JavaScript数组包含base 64编码图像,其中包含大小,类型等所有细节。我使用了$('#j_son')。val(JSON.stringify(AttachmentArray)); 每次填充数组时,在数组外部填充隐藏的输入字段(输入unhidden以显示JSON字符串)。使用HTML5和客户端脚本进行缩略图预览的轻量级多文件上载

提交时,我将使用PHP解码新的JSON字符串,并将多个图像放在名为uploads的文件夹中。

我面临的问题是,选择大于200 KB的图像附件似乎会减慢div容器内图像的输出和隐藏输入字段内的JSON字符串,而任何大的内容都会导致chrome内部出现“aw snap”错误并导致崩溃浏览器,我不知道我哪里出错了。我还有一个点击事件,当用户单击X删除按钮并且隐藏的输入字段使用更新的JSON数组重新填充时,如果文件很大,这将非常慢并且崩溃。PHP方面解决JSON字符串没有问题,它似乎落在JavaScript代码或我在脚本底部添加的额外功能上。有没有办法阻止这种情况发生?我已经添加了完整的代码,包括PHP,如果有人想测试它。

<!DOCTYPE html> 
<html>
<head>
<title></title>
<meta charset="utf-8" />

<style>

    /*Copied from bootstrap to handle input file multiple*/
    .btn {
        display: inline-block;
        padding: 6px 12px;
        margin-bottom: 0;
        font-size: 14px;
        font-weight: normal;
        line-height: 1.42857143;
        text-align: center;
        white-space: nowrap;
        vertical-align: middle;
        cursor: pointer;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        background-image: none;
        border: 1px solid transparent;
        border-radius: 4px;
    }
    /*Also */
    .btn-success {
        border: 1px solid #c5dbec;
        background: #D0E5F5;
        font-weight: bold;
        color: #2e6e9e;
    }
    /* This is copied from https://github.com/blueimp/jQuery-File- 
   Upload/blob/master/css/jquery.fileupload.css */
    .fileinput-button {
        position: relative;
        overflow: hidden;
    }

        .fileinput-button input {
            position: absolute;
            top: 0;
            right: 0;
            margin: 0;
            opacity: 0;
            -ms-filter: 'alpha(opacity=0)';
            font-size: 200px;
            direction: ltr;
            cursor: pointer;
        }

    .thumb {
        height: 80px;
        width: 100px;
        border: 1px solid #000;
    }

    ul.thumb-Images li {
        width: 120px;
        float: left;
        display: inline-block;
        vertical-align: top;
        height: 120px;
    }

    .img-wrap {
        position: relative;
        display: inline-block;
        font-size: 0;
    }

        .img-wrap .close {
            position: absolute;
            top: 2px;
            right: 2px;
            z-index: 100;
            background-color: #D0E5F5;
            padding: 5px 2px 2px;
            color: #000;
            font-weight: bolder;
            cursor: pointer;
            opacity: .5;
            font-size: 23px;
            line-height: 10px;
            border-radius: 50%;
        }

        .img-wrap:hover .close {
            opacity: 1;
            background-color: #ff0000;
        }

    .FileNameCaptionStyle {
        font-size: 12px;
    }
    </style>

    <script type="text/javascript" src="scripts/jquery-1.10.2.js"></script>
    <script type="text/javascript">

    //I added event handler for the file upload control to access the files 
    properties.
    document.addEventListener("DOMContentLoaded", init, false);

    //To save an array of attachments 
    var AttachmentArray = [];

    $('#j_son').val(JSON.stringify(AttachmentArray));

    //counter for attachment array
    var arrCounter = 0;

    //to make sure the error message for number of files will be shown only 
    one time.
    var filesCounterAlertStatus = false;

    //un ordered list to keep attachments thumbnails
    var ul = document.createElement('ul');
    ul.className = ("thumb-Images");
    ul.id = "imgList";

    function init() {
        //add javascript handlers for the file upload event
        document.querySelector('#files').addEventListener('change', 
    handleFileSelect, false);
    }

    //the handler for file upload event
    function handleFileSelect(e) {
        //to make sure the user select file/files
        if (!e.target.files) return;

        //To obtaine a File reference
        var files = e.target.files;

        // Loop through the FileList and then to render image files as 
        thumbnails.
        for (var i = 0, f; f = files[i]; i++) {

            //instantiate a FileReader object to read its contents into 
            memory
            var fileReader = new FileReader();

            // Closure to capture the file information and apply validation.
            fileReader.onload = (function (readerEvt) {
                return function (e) {

                    //Apply the validation rules for attachments upload
                    ApplyFileValidationRules(readerEvt)

                    //Render attachments thumbnails.
                    RenderThumbnail(e, readerEvt);

                    //Fill the array of attachment
                    FillAttachmentArray(e, readerEvt)
                };
            })(f);

            // Read in the image file as a data URL.
            // readAsDataURL: The result property will contain the 
            //file/blob's data encoded as a data URL.
            // More info about Data URI scheme 
            //https://en.wikipedia.org/wiki/Data_URI_scheme
            fileReader.readAsDataURL(f);
        }
        document.getElementById('files').addEventListener('change', 
    handleFileSelect, false);
    }

    //To remove attachment once user click on x button
    jQuery(function ($) {
        $('div').on('click', '.img-wrap .close', function () {
            var id = $(this).closest('.img-wrap').find('img').data('id');

            //to remove the deleted item from array
            var elementPos = AttachmentArray.map(function (x) { return 
            x.FileName; }).indexOf(id);
            if (elementPos !== -1) {
                AttachmentArray.splice(elementPos, 1);
            }

            //to remove image tag
            $(this).parent().find('img').not().remove();

            //to remove div tag that contain the image
            $(this).parent().find('div').not().remove();

            //to remove div tag that contain caption name
            $(this).parent().parent().find('div').not().remove();

            //to remove li tag
            var lis = document.querySelectorAll('#imgList li');
            for (var i = 0; li = lis[i]; i++) {
                if (li.innerHTML == "") {
                    li.parentNode.removeChild(li);
                }
            }

        });
    }
    )

    //Apply the validation rules for attachments upload
    function ApplyFileValidationRules(readerEvt)
    {
        //To check file type according to upload conditions
        if (CheckFileType(readerEvt.type) == false) {
            alert("The file (" + readerEvt.name + ") does not match the 
            upload conditions, You can only upload jpg/png/gif files");
            e.preventDefault();
            return;
        }

        //To check file Size according to upload conditions
        if (CheckFileSize(readerEvt.size) == false) {
            alert("The file (" + readerEvt.name + ") does not match the 
            upload conditions, The maximum file size for uploads should not 
            exceed 300 KB");
            e.preventDefault();
            return;
        }

        //To check files count according to upload conditions
        if (CheckFilesCount(AttachmentArray) == false) {
            if (!filesCounterAlertStatus) {
                filesCounterAlertStatus = true;
                alert("You have added more than 10 files. According to 
                upload conditions you can upload 10 files maximum");
            }
            e.preventDefault();
            return;
        }
    }

    //To check file type according to upload conditions
    function CheckFileType(fileType) {
        if (fileType == "image/jpeg") {
            return true;
        }
        else if (fileType == "image/png") {
            return true;
        }
        else if (fileType == "image/gif") {
            return true;
        }
         else if (fileType == "image/jpg") {
            return true;
        }
        else {
            return false;
        }
        return true;
    }

    //To check file Size according to upload conditions
    function CheckFileSize(fileSize) {
        if (fileSize < 2000000) {
            return true;
        }
        else {
            return false;
        }
        return true;
    }

    //To check files count according to upload conditions
    function CheckFilesCount(AttachmentArray) {
        //Since AttachmentArray.length return the next available index in 
        //the array, 
        //I have used the loop to get the real length
        var len = 0;
        for (var i = 0; i < AttachmentArray.length; i++) {
            if (AttachmentArray[i] !== undefined) {
                len++;
            }
        }
        //To check the length does not exceed 10 files maximum
        if (len > 9) {
            return false;
        }
        else
        {
            return true;
        }
    }

    //Render attachments thumbnails.
    function RenderThumbnail(e, readerEvt)
    {
        var li = document.createElement('li');
        ul.appendChild(li);
        li.innerHTML = ['<div class="img-wrap"> <span class="close">&times; 
        </span>' +
            '<img class="thumb" src="', e.target.result, '" title="', 
            escape(readerEvt.name), '" data-id="',
            readerEvt.name, '"/>' + '</div>'].join('');

        var div = document.createElement('div');
        div.className = "FileNameCaptionStyle";
        li.appendChild(div);
        div.innerHTML = [readerEvt.name].join('');
        document.getElementById('Filelist').insertBefore(ul, null);
    }

    //Fill the array of attachment
    function FillAttachmentArray(e, readerEvt)
    {
        AttachmentArray[arrCounter] =
        {
            AttachmentType: 1,
            ObjectType: 1,
            FileName: readerEvt.name,
            FileDescription: "Attachment",
            NoteText: "",
            MimeType: readerEvt.type,
            Content: e.target.result.split("base64,")[1],
            FileSizeInBytes: readerEvt.size,
        };
        arrCounter = arrCounter + 1;

        //THIS IS THE PART I ADDED TO POPULATE THE HIDDEN INPUT FIELD
        $('#j_son').val(JSON.stringify(AttachmentArray));
    }

    //THIS IS TO UPDATE THE INPUT FIELD WHEN A FILE IS REMOVED
    $(document).on('click', '.close', function(){
        var myString = JSON.stringify(AttachmentArray);
        $('#j_son').val(myString); 
    });


</script>

</head>
<body>
<div>
    <label style="font-size: 14px;">
        <span style='color:navy;font-weight:bold'>Attachment Instructions : 
</span>
    </label>

    <ul>
        <li>
            Allowed only files with extension (jpg, png, gif)
        </li>
        <li>
            Maximum number of allowed files 10 with 2 MB for each
        </li>
        <li>
            you can select files from different folders
        </li>
    </ul>
     <form method="POST" action="" enctype="multipart/form-data">
    <span class="btn btn-success fileinput-button">
        <span>Select Attachment</span>
        <input type="file" name="files[]" id="files" multiple 
        accept="image/jpeg, image/jpg image/png, image/gif,"><br />
    </span>

        <!--input field to be populated by the array-->
        <input type="text" name="j_son"  id="j_son" style="width: 500px;"> 

        <!--Submit and post to get decoded JSON string-->
        <button type="submit" id="image_post" name="post_it">Submit</button>

    </form>
    <output id="Filelist"></output>

</div>


<?php 

if(isset($_POST['post_it']))
{
    //other input fields

    $file = $_POST['j_son'];

    $tempData = html_entity_decode($file);
    $cleanData = json_decode($tempData, true);

    foreach($cleanData as $p)
    {
        echo $p['Content']."</br>";

        //insert code to uploads folder
    }
}
?>
</body>
</html>
提问于
用户回答回答于

- 编辑 -

这可能是因为chrome中的已知问题。尝试使用本文中推荐的blob

javascript如何上传blob?

function uploadAudio( blob ) {
  var reader = new FileReader();
  reader.onload = function(event){
    var fd = {};
    fd["fname"] = "test.wav";
    fd["data"] = event.target.result;
    $.ajax({
      type: 'POST',
      url: 'upload.php',
      data: fd,
      dataType: 'text'
    }).done(function(data) {
        console.log(data);
    });
  };
  reader.readAsDataURL(blob);
}

- /编辑 -

好吧,好像你正在多次向“files”id添加一个onChange事件监听器。一旦进入init,每次调用handleFileSelect函数一次。这肯定是你的减速问题。

此外,如果您要将文件上载大小最大为2MB,则应使用upload_max_filesize在PHP文件中设置此值,并设置post_max_size。

ini_set('upload_max_filesize', '2M');
ini_set('post_max_size', '2M');

来自php.net:

的upload_max_filesize 上传文件的最大大小。 的post_max_size 设置允许的后期数据的最大大小。此设置也会影响文件上载。要上传大文件,此值必须大于upload_max_filesize。一般来说,memory_limit应该大于post_max_size。使用整数时,该值以字节为单位。

此外,如果您的上传结束超时,您可能还希望通过使用max_input_time或max_execution时间来延长执行时间,尽管我认为max_input_time应该足够了。

ini_set('max_input_time',300); ini_set('max_execution_time',300);

max_input_time设置 这将设置允许脚本解析输入数据的最长时间(以秒为单位),如POST和GET。定时从服务器上调用PHP开始,到执行开始时结束。默认设置为-1,表示使用max_execution_time。设置为0以允许无限时间。 的max_execution_time 这将设置允许脚本在解析器终止之前运行的最长时间(以秒为单位)。这有助于防止写得不好的脚本占用服务器。默认设置为30.从命令行运行PHP时,默认设置为0。

这需要在其他输出之前添加到PHP文件的顶部。

扫码关注云+社区

领取腾讯云代金券