使用 AJAX、PHP 和 jQuery 上传多张图片

Posted

技术标签:

【中文标题】使用 AJAX、PHP 和 jQuery 上传多张图片【英文标题】:Upload multiple image using AJAX, PHP and jQuery 【发布时间】:2015-05-05 13:48:46 【问题描述】:

我在使用 AJAX 上传多张图片时遇到很多问题。我写了这段代码:

HTML

<form id="upload" method="post" enctype="multipart/form-data">
    <div id="drop" class="drop-area">
        <div class="drop-area-label">
            Drop image here
        </div>
        <input type="file" name="file" id="file" multiple/>
    </div>

    <ul class="gallery-image-list" id="uploads">
    <!-- The file uploads will be shown here -->
    </ul>
</form>
<div id="listTable"></div>

jQuery/AJAX

$(document).on("change", "input[name^='file']", function(e)
    e.preventDefault();
    var This    =   this,
        display =   $("#uploads");

    // list all file data
    $.each(This.files, function(i, obj)
        // for each image run script asynchronous
        (function(i) 
            // get data from input file
            var file = This.files[i],
                name = file.name,
                size = file.size,
                type = file.type,
                lastModified        =   file.lastModified,
                lastModifiedDate    =   file.lastModifiedDate,
                webkitRelativePath  =   file.webkitRelativePath,
                slice               =   file.slice,
                i = i;

            // DEBUG
       /*
            var acc = []
            $.each(file, function(index, value) 
                acc.push(index + ": " + value);
            );
            alert(JSON.stringify(acc));
        */

            $.ajax(
                url:'/ajax/upload.php',
                contentType: "multipart/form-data",
                data:
                        "image":
                        
                            "name":name,
                            "size":size,
                            "type":type,
                            "lastModified":lastModified,
                            "lastModifiedDate":lastModifiedDate,
                            "webkitRelativePath":webkitRelativePath,
                            //"slice":slice,
                        
                    ,
                type: "POST",
                // Custom XMLHttpRequest
                xhr: function() 
                    var myXhr = $.ajaxSettings.xhr();
                    // Check if upload property exists
                    if(myXhr.upload)
                    
                        // For handling the progress of the upload
                        myXhr.upload.addEventListener("progress",progressHandlingFunction, false); 
                    
                    return myXhr;
                ,
                cache: false,
                success : function(data)
                    // load ajax data
                    $("#listTable").append(data);
                
            );
            // display progress
            function progressHandlingFunction(e)
                if(e.lengthComputable)
                    var perc = Math.round((e.loaded / e.total)*100);
                    perc = ( (perc >= 100) ? 100 : ( (perc <= 0) ? 0 : 0 ) );
                $("#progress"+i+" > div")
                    .attr("aria-valuenow":perc)
                        .css("width", perc+"%");
                
            
            // display list of files
            display.append('<li>'+name+'</li><div class="progress" id="progress'+i+'">'
                    +'<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">'
                    +'</div></div>');
        )(i);
    ); 
);

我尝试了各种版本,但从未成功通过 ajax 发送多个数据。我已经以这种方式尝试了您在上面看到的内容,现在我只得到 POST 信息。我明白为什么我会收到 POST,但我需要发送 FILES 信息,但我不知道我错在哪里。

我不是第一次使用 ajax,并且经常将它用于大多数项目,但我从来没有发送过多个文件,现在这让我很困扰。

谢谢!

【问题讨论】:

请澄清: 1. contentType 是multipart/form-data 而data 不是(jQuery.param 会将js 对象转换为x-www-form-urlencoded 而不是),所以数据会在翻译中丢失。您要转移什么以及如何转移? 2. 没有上传实际图片数据,这是故意的吗? 3. 每个文件调用一个ajax,导致处理过程中的大量连接和冲突,这是故意的吗? 4. 我没有看到任何拖放代码。你想要吗? 【参考方案1】:

尝试利用json上传,处理file对象

html

<div id="drop" class="drop-area ui-widget-header">
  <div class="drop-area-label">Drop image here</div>
</div>
<br />
<form id="upload">
  <input type="file" name="file" id="file" multiple="true" accepts="image/*" />
  <ul class="gallery-image-list" id="uploads">
    <!-- The file uploads will be shown here -->
  </ul>
</form>
<div id="listTable"></div>

css

  #uploads 
      display:block;
      position:relative;
   

  #uploads li 
      list-style:none;
  

  #drop 
      width: 90%;
      height: 100px;
      padding: 0.5em;
      float: left;
      margin: 10px;
      border: 8px dotted grey;
  

  #drop.hover 
      border: 8px dotted green;
  

  #drop.err 
      border: 8px dotted orangered;
  

js

var display = $("#uploads"); // cache `#uploads`, `this` at `$.ajax()`
var droppable = $("#drop")[0]; // cache `#drop` selector
$.ajaxSetup(
    context: display,
    contentType: "application/json",
    dataType: "json",
    beforeSend: function (jqxhr, settings) 
        // pre-process `file`
        var file = JSON.parse(
                   decodeURIComponent(settings.data.split(/=/)[1])
                   );
        // add `progress` element for each `file`
        var progress = $("<progress />", 
                "class": "file-" + (!!$("progress").length 
                         ? $("progress").length 
                         : "0"),
                "min": 0,
                "max": 0,
                "value": 0,
                "data-name": file.name
        );
        this.append(progress, file.name + "<br />");
        jqxhr.name = progress.attr("class"); 
    
);

var processFiles = function processFiles(event) 
    event.preventDefault();
    // process `input[type=file]`, `droppable` `file`
    var files = event.target.files || event.dataTransfer.files;
    var images = $.map(files, function (file, i) 
        var reader = new FileReader();
        var dfd = new $.Deferred();
        reader.onload = function (e) 
            dfd.resolveWith(file, [e.target.result])
        ;
        reader.readAsDataURL(new Blob([file], 
            "type": file.type
        ));
        return dfd.then(function (data) 
            return $.ajax(
                type: "POST",
                url: "/echo/json/",
                data: 
                    "file": JSON.stringify(
                            "file": data,
                            "name": this.name,
                            "size": this.size,
                            "type": this.type
                    )
                ,
                xhr: function () 
                    // do `progress` event stuff
                    var uploads = this.context;
                    var progress = this.context.find("progress:last");
                    var xhrUpload = $.ajaxSettings.xhr();
                    if (xhrUpload.upload) 
                        xhrUpload.upload.onprogress = function (evt) 
                            progress.attr(
                                    "max": evt.total,
                                    "value": evt.loaded
                            )
                        ;
                        xhrUpload.upload.onloadend = function (evt) 
                            var progressData = progress.eq(-1);
                            console.log(progressData.data("name")
                                    + " upload complete...");
                            var img = new Image;
                            $(img).addClass(progressData.eq(-1)
                            .attr("class"));
                            img.onload = function () 
                                if (this.complete) 
                                  console.log(
                                      progressData.data("name")
                                      + " preview loading..."
                                  );
                                ;

                            ;
                        uploads.append("<br /><li>", img, "</li><br />");
                        ;
                    
                    return xhrUpload;
                
            )
            .then(function (data, textStatus, jqxhr) 
                console.log(data)
                this.find("img[class=" + jqxhr.name + "]")
                .attr("src", data.file)
                .before("<span>" + data.name + "</span><br />");
                return data
            , function (jqxhr, textStatus, errorThrown) 
                console.log(errorThrown);
                return errorThrown
            );
        )
    );
    $.when.apply(display, images).then(function () 
        var result = $.makeArray(arguments);
        console.log(result.length, "uploads complete");
    , function err(jqxhr, textStatus, errorThrown) 
        console.log(jqxhr, textStatus, errorThrown)
    )
;

$(document)
.on("change", "input[name^=file]", processFiles);
// process `droppable` events
droppable.ondragover = function () 
    $(this).addClass("hover");
    return false;
;

droppable.ondragend = function () 
    $(this).removeClass("hover")
    return false;
;

droppable.ondrop = function (e) 
    $(this).removeClass("hover");
    var image = Array.prototype.slice.call(e.dataTransfer.files)
        .every(function (img, i) 
        return /^image/.test(img.type)
    );
    e.preventDefault();
    // if `file`, file type `image` , process `file`
    if (!!e.dataTransfer.files.length && image) 
            $(this).find(".drop-area-label")
            .css("color", "blue")
            .html(function (i, html) 
            $(this).delay(3000, "msg").queue("msg", function () 
                $(this).css("color", "initial").html(html)
            ).dequeue("msg");
            return "File dropped, processing file upload...";
        );
        processFiles(e);
     else 
            // if dropped `file` _not_ `image`
            $(this)
            .removeClass("hover")
            .addClass("err")
            .find(".drop-area-label")
            .css("color", "darkred")
            .html(function (i, html) 
            $(this).delay(3000, "msg").queue("msg", function () 
                $(this).css("color", "initial").html(html)
                .parent("#drop").removeClass("err")
            ).dequeue("msg");
            return "Please drop image file...";
        );
    ;
;

php

<?php
  if (isset($_POST["file"])) 
    // do php stuff
    // call `json_encode` on `file` object
    $file = json_encode($_POST["file"]);
    // return `file` as `json` string
    echo $file;
  ;

jsfiddle http://jsfiddle.net/guest271314/0hm09yqo/

【讨论】:

问题,在 PHP 中,字符串 $file 我用于处理数据并且可以像使用 $_FILE[] 一样上传? @IvijanStefanStipić 不客气:) $file php 部分在帖子 not$_FILES 相同。 $_FILES 似乎需要 &lt;form&gt; 元素,带有 enctype="multipart/form-data" 属性。 post方法利用JSON数据类型post,处理响应。见php.net/manual/en/features.file-upload.post-method.php、w3.org/TR/html401/interact/forms.html#h-17.13.4.2、sitepoint.com/handle-file-uploads-php、***.com/questions/3586919/…。 我问是因为我想调整图像大小、重命名、制作拇指并保存在文件夹中。我会看看这个链接并尝试。再次感谢。 @IvijanStefanStipić 实际图像应该是data-uri developer.mozilla.org/en-US/docs/Web/HTTP/data_URIsfile.file,图像名称file.name

以上是关于使用 AJAX、PHP 和 jQuery 上传多张图片的主要内容,如果未能解决你的问题,请参考以下文章

php中上传多张图片,如何解决?

图片上传太慢php

如何使用 php jquery ajax 上传文件和插入数据

如何使用 PHP、jQuery 和 AJAX 上传多个文件

如何使用带有 json 和 php 的 jquery 的 $.ajax 函数上传文件

使用jQuery Ajax和PHP从URL上传图像