resumablejs 分块上传 断点续传
1 http://www.resumablejs.com/ 官网 2 upload.html 3 <!DOCTYPE html> 4 <html lang="en"> 5 6 <div> 7 <a href="#" id="browseButton" >Select files</a> 8 <div> 9 <div> 10 <input id="btnCancel" type="button" onClick='r.pause()'value="Cancel All Uploads" 11 style="margin-left: 2px; height: 22px; font-size: 8pt;" /> 12 <br /> 13 </div> 14 <script src="resumable.js"></script> 15 <script> 16 var r = new Resumable({ 17 target:'upload.php', 18 chunkSize:2*1024*1024, 19 simultaneousUploads:4, 20 testChunks:true, 21 throttleProgressCallbacks:1, 22 23 }); 24 25 r.assignBrowse(document.getElementById('browseButton')); 26 27 r.on('fileSuccess', function(file){ 28 // console.debug(file); 29 }); 30 r.on('fileProgress', function(file){ 31 // console.debug(file); 32 }); 33 r.on('fileAdded', function(file, event){ 34 r.upload(); 35 //console.debug(file, event); 36 }); 37 r.on('fileRetry', function(file){ 38 //console.debug(file); 39 }); 40 r.on('fileError', function(file, message){ 41 //console.debug(file, message); 42 }); 43 r.on('uploadStart', function(){ 44 //console.debug(); 45 }); 46 r.on('complete', function(){ 47 //console.debug(); 48 }); 49 r.on('progress', function(){ 50 //console.debug(); 51 }); 52 r.on('error', function(message, file){ 53 //console.debug(message, file); 54 }); 55 r.on('pause', function(file,message){ 56 //console.debug(); 57 58 }); 59 r.on('cancel', function(){ 60 //console.debug(); 61 }); 62 </script> 63 64 </html> 65 66 upload.php 67 <?php 68 /** 69 * This is the implementation of the server side part of 70 * Resumable.js client script, which sends/uploads files 71 * to a server in several chunks. 72 * 73 * The script receives the files in a standard way as if 74 * the files were uploaded using standard HTML form (multipart). 75 * 76 * This PHP script stores all the chunks of a file in a temporary 77 * directory (`temp`) with the extension `_part<#ChunkN>`. Once all 78 * the parts have been uploaded, a final destination file is 79 * being created from all the stored parts (appending one by one). 80 * 81 * @author Gregory Chris (http://online-php.com) 82 * @email www.online.php@gmail.com 83 */ 84 85 86 //////////////////////////////////////////////////////////////////// 87 // THE FUNCTIONS 88 //////////////////////////////////////////////////////////////////// 89 90 /** 91 * 92 * Logging operation - to a file (upload_log.txt) and to the stdout 93 * @param string $str - the logging string 94 */ 95 function _log($str) { 96 97 // log to the output 98 $log_str = date('d.m.Y').": {$str}\r\n"; 99 echo $log_str; 100 101 // log to file 102 if (($fp = fopen('upload_log.txt', 'a+')) !== false) { 103 fputs($fp, $log_str); 104 fclose($fp); 105 } 106 } 107 108 /** 109 * 110 * Delete a directory RECURSIVELY 111 * @param string $dir - directory path 112 * @link http://php.net/manual/en/function.rmdir.php 113 */ 114 function rrmdir($dir) { 115 if (is_dir($dir)) { 116 $objects = scandir($dir); 117 foreach ($objects as $object) { 118 if ($object != "." && $object != "..") { 119 if (filetype($dir . "/" . $object) == "dir") { 120 rrmdir($dir . "/" . $object); 121 } else { 122 unlink($dir . "/" . $object); 123 } 124 } 125 } 126 reset($objects); 127 rmdir($dir); 128 } 129 } 130 131 /** 132 * 133 * Check if all the parts exist, and 134 * gather all the parts of the file together 135 * @param string $dir - the temporary directory holding all the parts of the file 136 * @param string $fileName - the original file name 137 * @param string $chunkSize - each chunk size (in bytes) 138 * @param string $totalSize - original file size (in bytes) 139 */ 140 function createFileFromChunks($temp_dir, $fileName, $chunkSize, $totalSize) { 141 142 // count all the parts of this file 143 $total_files = 0; 144 foreach(scandir($temp_dir) as $file) { 145 if (stripos($file, $fileName) !== false) { 146 $total_files++; 147 } 148 } 149 150 // check that all the parts are present 151 // the size of the last part is between chunkSize and 2*$chunkSize 152 if ($total_files * $chunkSize >= ($totalSize - $chunkSize + 1)) { 153 154 // create the final destination file 155 if (($fp = fopen('temp/'.$fileName, 'w')) !== false) { 156 for ($i=1; $i<=$total_files; $i++) { 157 fwrite($fp, file_get_contents($temp_dir.'/'.$fileName.'.part'.$i)); 158 _log('writing chunk '.$i); 159 } 160 fclose($fp); 161 } else { 162 _log('cannot create the destination file'); 163 return false; 164 } 165 166 // rename the temporary directory (to avoid access from other 167 // concurrent chunks uploads) and than delete it 168 if (rename($temp_dir, $temp_dir.'_UNUSED')) { 169 rrmdir($temp_dir.'_UNUSED'); 170 } else { 171 rrmdir($temp_dir); 172 } 173 } 174 175 } 176 177 178 //////////////////////////////////////////////////////////////////// 179 // THE SCRIPT 180 //////////////////////////////////////////////////////////////////// 181 182 //check if request is GET and the requested chunk exists or not. this makes testChunks work 183 if ($_SERVER['REQUEST_METHOD'] === 'GET') { 184 185 $temp_dir = 'temp/'.$_GET['resumableIdentifier']; 186 $chunk_file = $temp_dir.'/'.$_GET['resumableFilename'].'.part'.$_GET['resumableChunkNumber']; 187 if (file_exists($chunk_file)) { 188 header("HTTP/1.0 200 Ok"); 189 } else 190 { 191 header("HTTP/1.0 404 Not Found"); 192 } 193 } 194 195 196 197 // loop through files and move the chunks to a temporarily created directory 198 if (!empty($_FILES)) foreach ($_FILES as $file) { 199 200 // check the error status 201 if ($file['error'] != 0) { 202 _log('error '.$file['error'].' in file '.$_POST['resumableFilename']); 203 continue; 204 } 205 206 // init the destination file (format <filename.ext>.part<#chunk> 207 // the file is stored in a temporary directory 208 $temp_dir = 'temp/'.$_POST['resumableIdentifier']; 209 $dest_file = $temp_dir.'/'.$_POST['resumableFilename'].'.part'.$_POST['resumableChunkNumber']; 210 211 // create the temporary directory 212 if (!is_dir($temp_dir)) { 213 mkdir($temp_dir, 0777, true); 214 } 215 216 // move the temporary file 217 if (!move_uploaded_file($file['tmp_name'], $dest_file)) { 218 _log('Error saving (move_uploaded_file) chunk '.$_POST['resumableChunkNumber'].' for file '.$_POST['resumableFilename']); 219 } else { 220 221 // check if all the parts present, and create the final destination file 222 createFileFromChunks($temp_dir, $_POST['resumableFilename'], 223 $_POST['resumableChunkSize'], $_POST['resumableTotalSize']); 224 } 225 }