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" > </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.