天天看點

無重新整理上傳檔案以及HTML5下的實作方式

版權聲明: 本文由 一隻部落格 發表于 bloghome部落格

文章連結: https://www.bloghome.com.cn/user/cnn237111

正常實作方法:

ajax無法實作上傳檔案,是以正常情況下,要實作無重新整理上傳檔案的做法,是在頁面隐藏一個iframe,然後将上傳form的target指向這個iframe,變相的實作。如下代碼:

<p id="uploading" style="display:none;">Uploading...<img src="loading.gif"/>
<form action="upload.php" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();" >
    File: <input name="myfile" type="file" />
          <input type="submit" name="submitBtn" value="Upload" />
</form>
<iframe id="upload_target" name="upload_target" src="#" style=";height:0;border:0px solid #fff;">
</iframe>      

upload_target是一個長寬都是0的iframe,是以頁面上看不見他。還需要配合js,使得效果更好:

<script>
function startUpload(){
   $('#uploading').show();
}
function finisheUpload(i){
   $('#uploading').hide();
   if(i==0)
   {
     alert("上傳成功");
    }
    else
   {
      alert("上傳失敗");
    }
}
</script>      

其中startUpload方法是在送出表單的時候觸發,而由于沒有什麼回調函數,是以finisheUpload隻能由upload.php檔案的輸出控制。通常就是在輸出中輸出一段javascript代碼來執行。

php代碼如下:

<?php
header("Content-Type:text/html;charset=utf-8");
$destination_path = getcwd().DIRECTORY_SEPARATOR;
$filname = $destination_path . basename( $_FILES['myfile']['name']);
$filname=iconv("UTF-8","gb2312",$filname);
if(move_uploaded_file($_FILES['myfile']['tmp_name'], $filname)) {
   echo "<script language=\"javascript\" type=\"text/javascript\">window.parent.finisheUpload(0);</script> ";
}
else
{
   echo "<script language=\"javascript\" type=\"text/javascript\">window.parent.finisheUpload(1);</script> ";
}      

注意,輸出javascript的時候,由于調用的js方法是在iframe外定義的,要在iframe内調用js方法,需要指定window.parent。

————————

HTML5下的實作方法:

先介紹一下FileReader對象:

FileReader對象的詳細說明可以在W3C官方文檔中檢視。

該接口提供方法來讀取檔案對象或者Blob對象。它繼承了EventTarget,接口的描述如下:

[Constructor]
    interface FileReader: EventTarget {
      // async read methods
      void readAsArrayBuffer(Blob blob);
      void readAsText(Blob blob, optional DOMString label);
      void readAsDataURL(Blob blob);
      void abort();
      // states
      const unsigned short EMPTY = 0;
      const unsigned short LOADING = 1;
      const unsigned short DONE = 2;
      readonly attribute unsigned short readyState;
      // File or Blob data
      readonly attribute (DOMString or ArrayBuffer)? result;
      readonly attribute DOMError? error;
      // event handler attributes
      attribute EventHandler       attribute EventHandler onprogress;
      attribute EventHandler       attribute EventHandler onabort;
      attribute EventHandler onerror;
      attribute EventHandler     };      
可以看到有4個異步方法,其中3個是讀取,1個是放棄,4個狀态屬性,1個result,1個error和6個事件。(之前還有readAsBinaryString方法,不過已經被W3C去除了)這6個事件的觸發時機如下:      

loadstart --When the read starts.

progress --While reading (and decoding) blob

abort --When the read has been aborted. For instance, by invoking the abort() method.

error --When the read has failed (see errors).

load --When the read has successfully completed.

loadend --When the request has completed (either in success or failure).

下面示範一個例子,讀取一個文本文檔,并且alert出來内容。

<script>
function readfile(dom)
{
    var file = dom.files[0];
    var textType = /text.*/;//正規表達式,使之比對text/html,text/plain
    if (file.type.match(textType)) {
    var reader = new FileReader();
    //注冊事件函數,即等讀完内容後,要做的事情
    reader.onload = function(e) {
        alert(reader.result);
    }
    //異步讀取内容
    reader.readAsText(file,'gb2312');
        $("#msg").html("正在執行異步讀取");
    }
    else {
        alert("檔案不支援");
    }
}
</script>
<input type="file" id="testfiles" name="files[]" onchange="readfile(this);" />
<div id="msg"></div>      

——————————————————————————————

下面示範一個例子,讀取一個DataURL的,DataURL其實是一種DataURI(要知道URI的更多細節,可以去http://css-tricks.com/data-uris/,或者維基百科了解更多)。它提供了一種在浏覽器中顯示資料的途徑。比如你要顯示一個圖檔(百度的logo)的話,你可以如下寫:

<img src="http://www.baidu.com/img/bdlogo.gif" />      

你也可以用它的URI去寫,如下:

<img src="data:p_w_picpath/gif;base64,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" />

src中填寫的字元串就是DataURI,格式如下:

data:[<mime type>][;charset=<charset>][;base64],<encoded data>

這種URI其實很有用的,可以減少HTTP請求,使得網站提速。是以擷取了URI的話就可以加載本地的圖像了。示例代碼如下:

<script>
function loadimg(dom)
{
    var file = dom.files[0];
    //正規表達式,使之比對p_w_picpath/jpeg等
    var p_w_picpathType = /p_w_picpath.*/;
    if (file.type.match(p_w_picpathType)) {
        var reader = new FileReader();
        reader.onload = function(e) {
        var img = new Image();
        img.src = reader.result;
        $("#divimg").append(img);
    }
    reader.readAsDataURL(file);
    }
    else {
        alert("檔案不支援");
    }
}
</script>
<input type="file" id="testfiles" name="files[]" onchange="loadimg(this);" />
<div id="divimg"></div>      

————————————————————————————————————

還有一個方法是readAsArrayBuffer,從字面就可以看出,是把檔案讀取到一個數組緩沖區。

使用readAsArrayBuffer這種方法實作上傳檔案

下面示範一個例子:

<script>
function upload()
{
    var file = $('#testfiles')[0].files[0];
    var reader = new FileReader();
    reader.onload = function (rResult) {
        var filename = file.name;
        var options = {
            type: 'POST',
            url: 'upload.php?filename='+filename,
            data: reader.result,
            success:function(result){
                alert(result.msg);
            },
            processData: false,  // 告訴jQuery不要去處理發送的資料
            contentType: false,   // 告訴jQuery不要去設定Content-Type請求頭
            dataType:"json"
        };
        $.ajax(options);
    };
    reader.readAsArrayBuffer(file);
}
</script>
<input type="button" value="upload" onclick="javascript:upload();"/>      

後端PHP代碼:

try{
    $filename=$_GET['filename'];
    $input = file_get_contents("php://input");  //這個是擷取請求的InputStream,PHP下的寫法
    file_put_contents($filename, $input);//儲存成檔案。
    echo json_encode(array("msg"=>"上傳成功"));
}
catch(Exception $e)
{
    echo json_encode(array("msg"=>"上傳失敗"));
}      

FormData方法

FromData的官方說明在這裡。利用

FormData

對象,你可以使用一系列的鍵值對來模拟一個完整的表單。

以下給出一個例子,允許上傳多個檔案:

<script>
function upload()
{
    var formdata = new FormData();
    $.each($('#testfiles')[0].files, function(i, file) {
    formdata.append('file-'+i, file);
    });
    var options = {
        type: 'POST',
        url: 'upload.php',
        data: formdata,
        success:function(result){
            alert(result.msg);
        },
        processData: false,  // 告訴jQuery不要去處理發送的資料
        contentType: false,   // 告訴jQuery不要去設定Content-Type請求頭
        dataType:"json"
    };
    $.ajax(options);
}
</script>
<input type="button" value="upload" onclick="javascript:upload();"/>      

背景PHP代碼:

try
{
    foreach($_FILES as $key => $value)
    {
        //print_r ($_FILES[$key]); echo "<br>";
        move_uploaded_file( $value["tmp_name"], $value['name']);
    }
        echo json_encode(array("msg"=>"上傳成功"));
}
catch(Exception $e)
{
    echo json_encode(array("msg"=>"上傳失敗"));
}      

參考文檔:

https://developer.mozilla.org/zh-CN/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects

http://dev.w3.org/2006/webapi/FileAPI/#FileReader-interface

上一篇: Log
下一篇: 測試

繼續閱讀