Front-end JS implementation of the file breakpoints to continue to receive _javascript PHP file received skills

Source: Internet
Author: User
Tags error handling

Long heard of the breakpoint extension of this thing, the front-end can also be achieved.

The implementation of the breakpoint on the front end relies mainly on the new features of the HTML5, so the support on the old browsers is generally not high.

This article through a simple example of the continuation of the breakpoint ( front-end file submission + back-end PHP file reception ), understand its general implementation process

Let's take a picture for example and look at the last appearance.

First, some knowledge preparation

Breakpoint continues to pass, since there is a break, that should have the process of file segmentation, a section of the biography.

Previous files could not be segmented, but with the introduction of new HTML5 features, similar to ordinary string, array segmentation, we can use the slice method to split the file.

Therefore, the most basic implementation of the breakpoint is: the front-end through the FileList object to obtain the corresponding file, according to the designated partition mode will be a large file segmentation, and then a paragraph to the back end, the back end in order a section of the file to be spliced.

And we need to modify the FileList object to submit, in the previous article, we know some of the points of attention to this submission, because the FileList object can not be directly changed, so can not directly through the form of the. Submit () method upload submission, You need to combine the Formdata object to generate a new data, upload through Ajax operation.

Second, the implementation process

This example implements the basic function of file breakpoint, but the manual "suspend upload" operation has not been successful, can refresh the page in the upload process to simulate the interruption of the upload, experience the "breakpoint continued transmission",

There may be some other minor bugs, but the basic logic is generally the same.

1. Front-End implementation

First select the file, listing the selected file list information, and then you can customize the upload operation

(1) So set the page DOM structure first

<!--uploaded form--> <form method= "POST" id= "MyForm" action= "/filetest.php" enctype= "Multipart/form-data" >
        <input type= "File" id= "MyFile" multiple> <!--uploaded files list--> <table id= "Upload-list" > <thead> <tr> <th width= "35%" > FileName </th> <th width= "15%" > File class
            Type </th> <th width= "15%" > File size </th> <th width= "20%" > Upload Progress </th> <th width= "15%" > <input type= "button" id= "upload-all-btn" value= "Upload all" > &LT;/TH&G
          T
    </tr> </thead> <tbody> </tbody> </table> </form> <!--the information template--> <script type= "text/template" id= "FILE-UPLOAD-TPL" for each file in the upload file list > <tr>
         ;td>{{filename}}</td> <td>{{fileType}}</td> <td>{{fileSize}}</td> <tdclass= "upload-progress" >{{progress}}</td> <td> <input type= "button" class= "upload-it Em-btn ' data-name= ' {{fileName}} ' data-size= ' {{totalsize}} ' data-state= ' default ' value= ' {{uploadval}} ' > </td > </tr> </script>

Here's a CSS style thrown out

<style type= "Text/css" > Body
      {
        font-family:arial;
      }
      form {
        margin:50px auto;
        width:600px;
      }

      Input[type= "button"] {
        cursor:pointer
      }
      Table {
        display:none;
        margin-top:15px;
        border:1px solid #ddd;
        border-collapse:collapse;
      }

      Table th {
        color: #666;
      }
      Table TD,
      table th {
        padding:5px;
        border:1px solid #ddd;
        Text-align:center;
        font-size:14px;
      }
    </style>

(2) Next is the implementation of JS analysis

We can get some information about the file through the FileList object

The size of which is the file sizes, the file partition fragmentation needs to rely on this

The size here is the byte number, so when the interface shows the file size, you can convert

Size of the calculated file
          = file.size > 1024
            file.size/1024 > 1024
            file.size/(1024 * 1024) > 1024
            ? (File.size/(1024 * 1024 * 1024)). ToFixed (2) + ' GB '
            : (File.size/(1024 * 1024)). ToFixed (2) + ' MB '
            : (file.size /1024). ToFixed (2) + ' KB '
            : (file.size). toFixed (2) + ' B ';

Select the file to display the file information, replace the data in the stencil

Update file Information list
          Uploaditem.push (Uploaditemtpl
            . Replace (/{{filename}}/g, File.name)
            . Replace (' {{ FileType}} ', File.type | | File.name.match (/\.\w+$/) + ' file ')
            . Replace (' {{fileSize}} ', size)
            . Replace (' {{Progress}} ', progress)
            . Replace (' {{totalsize}} ', File.size)
            . Replace (' {{uploadval}} ', Uploadval)
          );

However, when displaying file information, this file may have been uploaded before, in order to continue the transmission of the breakpoint, you need to judge and in the interface to make a prompt

Check to see if there is data locally (this is done when the local record is already uploaded 100%, it is simply uploading instead of uploading)

Initial through local records, to determine whether the file has been uploaded
          percent = Window.localStorage.getItem (file.name + ' _p ');

          If (percent && percent!== ' 100.0 ') {
            progress = ' uploaded ' + percent + '% ';
            Uploadval = ' Continue uploading ';
          }

Displays a list of file information

Click Start Upload, you can upload the corresponding file

When uploading files, you need to fragment the files

For example, the configuration of each section 1024B, a total of chunks paragraph (used to determine whether the last paragraph), paragraph chunk, the current percentage of uploaded percent, etc.

Need to mention is this suspend the upload operation, in fact I have not realized, pause not helpless ing ...

The next step is the staging process

Set the beginning end of a fragment
          var blobfrom = chunk * eachsize,//Sub start
            blobto = (chunk + 1) * eachsize > totalsize? totalsize: (chunk + 1) * eachsize,//segmented end
            percent = (* * blobto/totalsize). toFixed (1),//uploaded percentage
            timeout = 5000,//timeout Time
            fd = new FormData ($ (' #myForm ') [0]);

          Fd.append (' Thefile ', Findthefile (fileName). Slice (Blobfrom, blobto)); The document
          fd.append (' filename ', filename);//filename
          fd.append (' totalsize ', totalsize);//Total File size
          fd.append (' Islastchunk ', islastchunk); Whether is the last paragraph
          fd.append (' isfirstupload ', times = = ' first '? 1:0);//Whether it is the initial paragraph (first upload)

        //upload before the query whether and upload too much film
          Chunk = Window.localStorage.getItem (fileName + ' _chunk ') | | 0;
          Chunk = parseint (chunk, 10);

The file should support overlay upload, so if the file and upload is finished, and now upload, you should reset the data to support the overlay (no and then append the BLOB data directly)

If the first upload is the final fragment, that is, the file has been uploaded, then overwrite the upload
    if (times = = ' I ' && islastchunk = 1) {
    Window.localStorage.setItem (fileName + ' _chunk ', 0);
    chunk = 0;
    Islastchunk = 0;
  }

The Times is actually a parameter, because to pass the next fragment after the last fragment is passed, the practice here is to continue invoking the upload in the callback

Next is the real file upload operation, with Ajax upload, because the use of Formdata objects, so don't forget to $.ajax ({} Plus this configuration Processdata:false

Upload a section, through the return of the results to determine whether the upload completed, continue to upload

Success:function (rs) {rs = Json.parse (RS); Upload success if (rs.status = = 200) {//Record already uploaded percentage Window.localStorage.setItem (f

                Ilename + ' _p ', percent);
                  Already uploaded if (chunk = = (chunks-1)) {$progress. Text (msg[' done '));
                  $this. Val (' already uploaded '). Prop (' disabled ', true). CSS (' cursor ', ' not-allowed '); if (!$ (' #upload-list '). Find ('. Upload-item-btn:not (:d isabled) '). Length) {$ (' #upload-all-btn '). Val (' already on
                  "). Prop (' disabled ', true). CSS (' cursor ', ' not-allowed '); } else {//record already uploaded fragment Window.localStorage.setItem (FileName + ' _chunk

                  ', ++chunk);
                  $progress. Text (msg[' in '] + percent + '% ');
                  This setting can be paused, but the dynamic settings will not pause after clicking.
                  if (chunk = =) {//ispaused = 1;
         // }         Console.log (ispaused);
                  if (!ispaused) {startupload (); 
                Failed to upload, upload failure in a number of cases, specific according to the actual set else if (Rs.status = = 500) {
              $progress. Text (msg[' failed ']);
            }, Error:function () {$progress. Text (msg[' failed '));
 }

To continue the next segment of the upload, the recursive operation, in order to pass the next section of the ground

Cut a picture.

This is the complete JS logic, the code a little bit of comment should not ugly understand it haha

<script type= "Text/javascript" src= "jquery.js" ></script> <script type= "Text/javascript" >//Full
          Part of the upload operation $ (document). On (' Click ', ' #upload-all-btn ', function () {//Not selected file if (!$ (' #myFile '). Val ()) {
        $ (' #myFile '). focus (); ///simulate clicking on other uploaded files else {$ (' #upload-list. upload-item-btn '). each (function () {$ (this
          ). Click ();
        });

      }
      }); Select File-Displays file information $ (' #myFile '). Change (function (e) {var file, Uploaditem = [], UPLOADITEMTP L = $ (' #file-upload-tpl '). HTML (), size, percent, progress = ' not uploaded ', Uploadval = ' Start

        Upload ';

          for (var i = 0, j = this.files.length I < J; ++i) {file = This.files[i];
          percent = undefined;
          Progress = ' not uploaded ';

          Uploadval = ' start uploading '; Size of the calculated file = file.size > 1024?
         file.size/1024 > 1024   ? File.size/(1024 * 1024) > 1024?
            (File.size/(1024 * 1024 * 1024)). ToFixed (2) + ' GB ': (File.size/(1024 * 1024)). ToFixed (2) + ' MB '

          : (file.size/1024). toFixed (2) + ' KB ': (file.size). toFixed (2) + ' B ';

          Initial through local records, to determine whether the file has been uploaded percent = Window.localStorage.getItem (file.name + ' _p ');
            If (percent && percent!== ' 100.0 ') {progress = ' uploaded ' + percent + '% ';
          Uploadval = ' Continue uploading ';
            //Update file Information list Uploaditem.push (UPLOADITEMTPL. Replace (/{{filename}}/g, File.name)
            . replace (' {{fileType}} ', File.type | | file.name.match (/\.\w+$/) + ' file '). Replace (' {{fileSize}} ', size) . replace (' {{Progress}} ', progress). Replace (' {{totalsize}} ', file.size). Replace (' {{Uploa
        Dval}} ', Uploadval);
        } $ (' #upload-list '). Children (' tbody '). HTML (Uploaditem.join ('))  . End (). Show ();

      }); /** * When uploading files, extract matching file entries * @param {String} filename needs to match filename * @return {filelist} matching file Item *

        /function Findthefile (fileName) {var files = $ (' #myFile ') [0].files, Thefile; for (var i = 0, j = files.length I < J ++i) {if (Files[i].name = = fileName) {thefile = files
            [i];
          Break } return thefile?
      Thefile: []; //Upload file $ (document). On (' click ', '. Upload-item-btn ', function () {var $this = $ (this), STA Te = $this. attr (' data-state '), msg = {done: ' Upload success ', failed: ' Upload failed ', in: ' Upload In ... ', paused: ' Pause ... '}, FileName = $this. attr (' Data-name '), $progress = $this
          . Closest (' tr '). Find ('. upload-progress '), eachsize = 1024, TotalSize = $this. attr (' data-size '), chunks = Math.ceil (totalsizE/eachsize), percent, chunk,//suspend upload operation ispaused = 0; Suspend upload operation//not implemented, the dynamic setting of the ispaused value does not prevent the invocation of the AJAX request below (state = = ' uploading ') {$this. val (' Continue
          Upload '). attr (' data-state ', ' paused ');
          $progress. Text (msg[' paused '] + percent + '% ');
          ispaused = 1;
        Console.log (' pause: ', ispaused); //start/Continue uploading operations else if (state = = ' paused ' | | = state = = ' default ') {$this. val (' suspend upload '). attr (' d
          Ata-state ', ' uploading ');
        ispaused = 0;

        ///First click Upload startupload (' a '); Upload operation times: number of function startupload (time) {//upload before query is as well as upload chunk = Window.localstorag E.getitem (fileName + ' _chunk ') | |
          0;
          Chunk = parseint (chunk, 10);

          Determine if the end fragment var Islastchunk = (Chunk = = (chunks-1)? 1:0); If the first upload is the end of the fragment, that is, the file has been uploaded, then overwrite upload if (times = = "a" && Islastchunk = = 1) {Window.localStorage.setItem (fileName + ' _chunk ', 0);
            chunk = 0;
          Islastchunk = 0; //Set the beginning end of the fragment var blobfrom = chunk * eachsize,//Sub Start blobto = (chunk + 1) * Eachsize > totalsize?
            TotalSize: (chunk + 1) * eachsize,//segmented end percent = (* blobto/totalsize). toFixed (1),//% uploaded

          Timeout = 5000,//timeout time FD = new FormData ($ (' #myForm ') [0]); Fd.append (' Thefile ', Findthefile (fileName). Slice (Blobfrom, blobto)); The document fd.append (' filename ', filename); FileName fd.append (' totalsize ', totalsize); Total file Size fd.append (' Islastchunk ', islastchunk); Is the last segment Fd.append (' Isfirstupload ', times = = ' 1:0 ');
            is the first paragraph (first upload)//upload $.ajax ({type: ' post ', url: '/filetest.php ', DATA:FD, Processdata:false, Contenttype:falSE, Timeout:timeout, success:function (rs) {rs = Json.parse (RS); Upload success if (rs.status = = 200) {//Record already uploaded percentage Window.localStorage.setItem (f

                Ilename + ' _p ', percent);
                  Already uploaded if (chunk = = (chunks-1)) {$progress. Text (msg[' done '));
                  $this. Val (' already uploaded '). Prop (' disabled ', true). CSS (' cursor ', ' not-allowed '); if (!$ (' #upload-list '). Find ('. Upload-item-btn:not (:d isabled) '). Length) {$ (' #upload-all-btn '). Val (' already on
                  "). Prop (' disabled ', true). CSS (' cursor ', ' not-allowed '); } else {//record already uploaded fragment Window.localStorage.setItem (FileName + ' _chunk

                  ', ++chunk);
                  $progress. Text (msg[' in '] + percent + '% ');
                  This setting can be paused, but the dynamic settings will not pause after clicking. if (chunk = =) {//Ispaused = 1;
                  } console.log (ispaused);
                  if (!ispaused) {startupload (); 
                Failed to upload, upload failure in a number of cases, specific according to the actual set else if (Rs.status = = 500) {
              $progress. Text (msg[' failed ']);
            }, Error:function () {$progress. Text (msg[' failed '));
        }
          });

    }
      });
 </script>

2. Back-end implementation

Here the backend implementation is relatively simple, mainly rely on the file_put_contents, file_get_contents these two methods

To pay attention to, through the Formdata object uploaded file object, in PHP is also through the $_files global object to obtain, and to avoid uploading files in Chinese garbled, use the Iconv

The breakpoint continues to overwrite the supporting file, so if you already have the complete file, delete it

If the file already exists the first time it is uploaded, delete the file and upload the
    if ($isFirstUpload = = ' 1 ' && file_exists (' upload/'. $fileName) && FileSize (' upload/'. $fileName) = = $totalSize) {
      unlink (' upload/'. $fileName);
    }

Using the above two methods, the file information is appended, don't forget to add file_append this parameter ~

Continue appending file Data
    if (!file_put_contents (' upload/'. $fileName, file_get_contents ($_files[' thefile '] [' tmp_name ']), File_append) {
      $status = 501
    } else {
      //When the last fragment is uploaded, the detection file is complete (size is consistent)
      if ($isLastChunk = = ' 1 ') {
        if (FileSize (' upload/'. $fileName) = = $totalSize) {
          $status =;
        } else {
          $status = 502;}}
      else {
        $status =.
    }}

Generally after the transfer will need to check the file, so here is a simple check the file size is consistent

Depending on the actual requirements of different methods of error handling, here is not much to deal with

The Complete PHP section

<?php header (' Content-type:text/plain; Charset=utf-8 ');
  $files = $_files[' thefile '];
  $fileName = Iconv (' utf-8 ', ' GBK ', $_request[' fileName '));
  $totalSize = $_request[' totalsize '];
  $isLastChunk = $_request[' Islastchunk '];

  $isFirstUpload = $_request[' isfirstupload '];
  if ($_files[' thefile '] [' ERROR '] > 0) {$status = 500; else {//Here is the general file upload operation//if (!move_uploaded_file ($_files[' thefile '] [' tmp_name '], ' upload/'. $_files[' thefile '] [
    ' Name ']) {//$status = 501;
    else {//$status = 200; //The following section is a file breakpoint extension operation//If the file already exists when the first upload is made, delete the file and upload it again if ($isFirstUpload = = ' 1 ' && file_exists (' Uploa D/'.
    $fileName) && filesize (' upload/'. $fileName) = = $totalSize) {unlink (' upload/'. $fileName); //Otherwise continue appending file data if (!file_put_contents (' upload/'. $fileName, file_get_contents ($_files[' thefile '] [' tmp_name ']), F
    Ile_append)) {$status = 501;
    else {///when the last fragment is uploaded, detect if the file is complete (size is consistent)  if ($isLastChunk = = ' 1 ') {if (filesize (' upload/'. $fileName) = = $totalSize) {$status = 200;
        else {$status = 502;
      } else {$status = 200;
    } Echo json_encode (' status ' => $status, ' totalsize ' => filesize (' upload/'. $fileName),

' Islastchunk ' => $isLastChunk));
 ?>

Come here first!

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.