简体   繁体   English

多个图像上传JavaScript数组Stringify与大型图像作斗争base64

[英]Multiple image upload JavaScript array Stringify struggles with large images base64

I'm trying to add a multiple image up-loader which returns a JavaScript array that is populated by the user selecting images. 我正在尝试添加一个多图像上载器,该上载器返回一个JavaScript数组,该数组由用户选择图像填充。 I will be using this image up-loader with other input form elements which will all submit together, in this case i'm not using AJAX. 我将使用此图像上载器以及其他所有将一起提交的输入表单元素,在这种情况下,我不使用AJAX。 The maximum file upload size is 2MB. 文件最大上传大小为2MB。 The JavaScript array contains the base 64 encoded image with all the details including size, type etc. I have used $('#j_son').val(JSON.stringify(AttachmentArray)); JavaScript数组包含基本64位编码的图像,其中包括大小,类型等所有详细信息。我使用了$('#j_son')。val(JSON.stringify(AttachmentArray)); outside the array to populate the hidden input field everytime the array is populated (input unhidden to show JSON string). 每次在数组外部填充数组时都会填充隐藏的输入字段(取消隐藏输入以显示JSON字符串)。 Lightweight Multiple File Upload with Thumbnail Preview using HTML5 and Client Side Scripts 使用HTML5和客户端脚本通过缩略图预览进行轻量级多文件上传

在此处输入图片说明

On submit I will use PHP to decode the new JSON string and and put the multiple images in a folder called uploads. 提交后,我将使用PHP解码新的JSON字符串,并将多个图像放入一个名为uploads的文件夹中。

The problem I am facing is that selecting image attachments larger than 200 KB seem to slow the output of images inside the div container and the JSON string inside the hidden input field and anything to large will cause "aw snap" error inside chrome and crash the browser, I don't know where I'm going wrong. 我面临的问题是,选择大于200 KB的图像附件似乎会减慢div容器内图像的输出以及隐藏输入字段内的JSON字符串的速度,任何较大的操作都会导致chrome内的“ aw snap”错误并导致崩溃浏览器,我不知道哪里出了问题。 I also have a click event that when the user clicks X remove button and the hidden input field is repopulated with the updated JSON array, this to is really slow and crashes if the files are to large. 我还有一个click事件,当用户单击X remove按钮,并且用更新的JSON数组重新填充隐藏的输入字段时,这确实很慢,并且如果文件很大,则会崩溃。 The PHP side of things has no problem decoding the JSON string it seems to either fall on the JavaScript code or the extra functionality I have added at the bottom of the script. PHP方面对解码JSON字符串没有问题,它似乎属于JavaScript代码或我在脚本底部添加的额外功能。 Is there a way to stop this from happening? 有没有办法阻止这种情况的发生? I have added the full code including the PHP if anybody wants to test it. 如果有人要测试它,我已经添加了完整的代码,包括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>

-- edit -- -编辑-

This may be because of a known issue in chrome. 这可能是由于chrome中的一个已知问题。 Try using a blob as recommended in this post 尝试按照本文中的建议使用Blob

How can javascript upload a 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);
}

-- /edit -- -/编辑-

ok it seems like you are adding an onChange event listener multiple times to the "files" id. 好的,好像您要向“文件” ID多次添加onChange事件侦听器。 Once in the init and once every time the handleFileSelect function is called. 一次初始化,每次调用handleFileSelect函数。 This could for sure be your slowdown problem. 这肯定是您的减速问题。

Also, if you are going to have a file upload size that maxes out at 2MB you should set this in your PHP file using upload_max_filesize and also set post_max_size. 另外,如果文件上传大小最大为2MB,则应在PHP文件中使用upload_max_filesize进行设置,并设置post_max_size。

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

from php.net: 来自php.net:

upload_max_filesize 的upload_max_filesize

The maximum size of an uploaded file. 上载文件的最大大小。

post_max_size 的post_max_size

Sets max size of post data allowed. 设置允许的帖子数据的最大大小。 This setting also affects file upload. 此设置还会影响文件上传。 To upload large files, this value must be larger than upload_max_filesize. 要上传大文件,此值必须大于upload_max_filesize。 Generally speaking, memory_limit should be larger than post_max_size. 一般而言,memory_limit应该大于post_max_size。 When an integer is used, the value is measured in bytes. 使用整数时,该值以字节为单位。

Also if your upload ends up timing out you might also want to extend the execution time by using max_input_time or max_execution time though I think that max_input_time should be enough. 另外,如果您的上传最终超时,您可能还希望通过使用max_input_time或max_execution time来延长执行时间,尽管我认为max_input_time应该足够了。

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

max_input_time max_input_time设置

This sets the maximum time in seconds a script is allowed to parse input data, like POST and GET. 这设置了允许脚本解析输入数据(如POST和GET)的最长时间(以秒为单位)。 Timing begins at the moment PHP is invoked at the server and ends when execution begins. 计时从在服务器上调用PHP的那一刻开始,到执行开始时结束。 The default setting is -1, which means that max_execution_time is used instead. 默认设置为-1,这意味着将使用max_execution_time。 Set to 0 to allow unlimited time. 设置为0以允许无限的时间。

max_execution_time 的max_execution_time

This sets the maximum time in seconds a script is allowed to run before it is terminated by the parser. 这设置了允许脚本在解析器终止之前运行的最长时间(以秒为单位)。 This helps prevent poorly written scripts from tying up the server. 这有助于防止编写不正确的脚本占用服务器。 The default setting is 30. When running PHP from the command line the default setting is 0. 默认设置为30。从命令行运行PHP时,默认设置为0。

This needs to be added at the top of your PHP file before other output. 这需要在其他输出之前添加到PHP文件的顶部。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM