Thinkphp拖拽上传文件-使用webuploader插件(自己改动了一些地方)——分片上传

  1. html页面:
  2. <!DOCTYPE html>
  3. <html class="js cssanimations">
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  6. <title>Thinkphp拖拽上传文件-使用webuploader插件</title>
  7. <include file="Inc/css" />
  8. <link rel="stylesheet" href="__PUBLIC__/webuploader/xb-webuploader.css">
  9. <script src="__PUBLIC__/js/jquery.min.js"></script>
  10. <script src="__PUBLIC__/webuploader/webuploader.min.js"></script>
  11. </head>
  12. <body>
  13. <div class="admin-content">
  14. <form action="{:U('Mafull/webuploader')}" method="post" >
  15. <div id="upload-57c79f4938104" class="xb-uploader">
  16. <input type="hidden"  name="image" id="image">
  17. <div class="queueList">
  18. <div class="placeholder" style="padding: 20px">
  19. <div class="filePicker"></div>
  20. </div>
  21. </div>
  22. <div class="statusBar" style="display:none;">
  23. <div class="progress">
  24. <span class="text">0%</span>
  25. <span class="percentage"></span>
  26. </div>
  27. <div class="info"></div>
  28. <!-- <div class="btns">
  29. <div class="uploadBtn">开始上传</div>
  30. </div>-->
  31. </div>
  32. </div>
  33. </div>
  34. </form>
  35. </div>
  36. <script>
  37. /*上传文件操作  开始*/
  38. jQuery(function() {
  39. var $ = jQuery,    // just in case. Make sure it's not an other libaray.
  40. $wrap = $("#upload-57c79f4938104"),
  41. // 图片容器
  42. $queue = $('<ul class="filelist"></ul>')
  43. .appendTo( $wrap.find('.queueList') ),
  44. // 状态栏,包括进度和控制按钮
  45. $statusBar = $wrap.find('.statusBar'),
  46. // 文件总体选择信息。
  47. $info = $statusBar.find('.info'),
  48. // 上传按钮
  49. $upload = $wrap.find('.uploadBtn'),
  50. // 没选择文件之前的内容。
  51. $placeHolder = $wrap.find('.placeholder'),
  52. // 总体进度条
  53. $progress = $statusBar.find('.progress').hide(),
  54. // 添加的文件数量
  55. fileCount = 0,
  56. // 添加的文件总大小
  57. fileSize = 0,
  58. // 优化retina, 在retina下这个值是2
  59. ratio = window.devicePixelRatio || 1,
  60. // 缩略图大小
  61. thumbnailWidth = 110 * ratio,
  62. thumbnailHeight = 110 * ratio,
  63. // 可能有pedding, ready, uploading, confirm, done.
  64. state = 'pedding',
  65. // 所有文件的进度信息,key为file id
  66. percentages = {},
  67. supportTransition = (function(){
  68. var s = document.createElement('p').style,
  69. r = 'transition' in s ||
  70. 'WebkitTransition' in s ||
  71. 'MozTransition' in s ||
  72. 'msTransition' in s ||
  73. 'OTransition' in s;
  74. s = null;
  75. return r;
  76. })(),
  77. // WebUploader实例
  78. uploader;
  79. if ( !WebUploader.Uploader.support() ) {
  80. alert( 'Web Uploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器');
  81. throw new Error( 'WebUploader does not support the browser you are using.' );
  82. }
  83. // 实例化
  84. uploader = WebUploader.create({
  85. auto: true,// 选完文件后,是否自动上传。
  86. compress:false,
  87. pick: {
  88. id: "#upload-57c79f4938104 .filePicker",
  89. label: '点击选择文件',
  90. multiple : true
  91. },
  92. dnd: "#upload-57c79f4938104 .queueList",
  93. paste: document.body,
  94. // swf文件路径
  95. swf: BASE_URL + '/Uploader.swf',
  96. disableGlobalDnd: true,// [可选] [默认值:false]是否禁掉整个页面的拖拽功能,如果不禁用,图片拖进来的时候会默认被浏览器打开。
  97. server: "__URL__/ajax_upload",
  98. chunked: true,//是否切片
  99. chunkSize:10*1024*1024,
  100. fileNumLimit: 1,
  101. fileSizeLimit: 1024 * 1024 * 1024,    // 1G
  102. fileSingleSizeLimit: 1024 * 1024 * 1024    // 1G
  103. });
  104. // 当有文件添加进来时执行,负责view的创建
  105. function addFile( file ) {
  106. var $li = $( '<li id="' + file.id + '">' +
  107. '<p class="title">' + file.name + '</p>' +
  108. '<p class="imgWrap"></p>'+
  109. '<p class="progress"><span></span></p>' +
  110. '</li>' ),
  111. $btns = $('<div class="file-panel">' +
  112. '<span class="cancel">删除</span>' +
  113. '<span class="rotateRight">向右旋转</span>' +
  114. '<span class="rotateLeft">向左旋转</span></div>').appendTo( $li ),
  115. $prgress = $li.find('p.progress span'),
  116. $wrap = $li.find( 'p.imgWrap' ),
  117. $info = $('<p class="error"></p>'),
  118. showError = function( code ) {
  119. switch( code ) {
  120. case 'exceed_size':
  121. text = '文件大小超出';
  122. break;
  123. case 'interrupt':
  124. text = '上传暂停';
  125. break;
  126. default:
  127. text = '上传失败,请重试';
  128. break;
  129. }
  130. $info.text( text ).appendTo( $li );
  131. };
  132. if ( file.getStatus() === 'invalid' ) {
  133. showError( file.statusText );
  134. } else {
  135. // @todo lazyload
  136. $wrap.text( '预览中' );
  137. uploader.makeThumb( file, function( error, src ) {
  138. if ( error ) {
  139. $wrap.text( '不能预览' );
  140. return;
  141. }
  142. var img = $('<img src="'+src+'">');
  143. $wrap.empty().append( img );
  144. }, thumbnailWidth, thumbnailHeight );
  145. percentages[ file.id ] = [ file.size, 0 ];
  146. file.rotation = 0;
  147. }
  148. file.on('statuschange', function( cur, prev ) {
  149. if ( prev === 'progress' ) {
  150. $prgress.hide().width(0);
  151. } else if ( prev === 'queued' ) {
  152. $li.off( 'mouseenter mouseleave' );
  153. $btns.remove();
  154. }
  155. // 成功
  156. if ( cur === 'error' || cur === 'invalid' ) {
  157. console.log( file.statusText );
  158. showError( file.statusText );
  159. percentages[ file.id ][ 1 ] = 1;
  160. } else if ( cur === 'interrupt' ) {
  161. showError( 'interrupt' );
  162. } else if ( cur === 'queued' ) {
  163. percentages[ file.id ][ 1 ] = 0;
  164. } else if ( cur === 'progress' ) {
  165. $info.remove();
  166. $prgress.css('display', 'block');
  167. } else if ( cur === 'complete' ) {
  168. $li.append( '<span class="success"></span>' );
  169. }
  170. $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur );
  171. });
  172. $li.on( 'mouseenter', function() {
  173. $btns.stop().animate({height: 30});
  174. });
  175. $li.on( 'mouseleave', function() {
  176. $btns.stop().animate({height: 0});
  177. });
  178. $btns.on( 'click', 'span', function() {
  179. var index = $(this).index(),
  180. deg;
  181. switch ( index ) {
  182. case 0:
  183. uploader.removeFile( file );
  184. return;
  185. case 1:
  186. file.rotation += 90;
  187. break;
  188. case 2:
  189. file.rotation -= 90;
  190. break;
  191. }
  192. if ( supportTransition ) {
  193. deg = 'rotate(' + file.rotation + 'deg)';
  194. $wrap.css({
  195. '-webkit-transform': deg,
  196. '-mos-transform': deg,
  197. '-o-transform': deg,
  198. 'transform': deg
  199. });
  200. } else {
  201. $wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')');
  202. }
  203. });
  204. $li.appendTo( $queue );
  205. }
  206. // 负责view的销毁
  207. function removeFile( file ) {
  208. var $li = $('#'+file.id);
  209. delete percentages[ file.id ];
  210. updateTotalProgress();
  211. $li.off().find('.file-panel').off().end().remove();
  212. }
  213. function updateTotalProgress() {
  214. var loaded = 0,
  215. total = 0,
  216. spans = $progress.children(),
  217. percent;
  218. $.each( percentages, function( k, v ) {
  219. total += v[ 0 ];
  220. loaded += v[ 0 ] * v[ 1 ];
  221. } );
  222. percent = total ? loaded / total : 0;
  223. spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' );
  224. spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' );
  225. updateStatus();
  226. }
  227. function updateStatus() {
  228. var text = '', stats;
  229. if ( state === 'ready' ) {
  230. text = '选中' + fileCount + '个文件,共' +
  231. WebUploader.formatSize( fileSize ) + '。';
  232. } else if ( state === 'confirm' ) {
  233. stats = uploader.getStats();
  234. if ( stats.uploadFailNum ) {
  235. text = '已成功上传' + stats.successNum+ '个文件,'+
  236. stats.uploadFailNum + '个上传失败,<a class="retry" href="#">重新上传</a>失败文件或<a class="ignore" href="#">忽略</a>'
  237. }
  238. } else {
  239. stats = uploader.getStats();
  240. if(stats.successNum==0){
  241. text="";
  242. }
  243. else
  244. {
  245. text = '共' + fileCount + '个(' +
  246. WebUploader.formatSize( fileSize )  +
  247. '),已上传' + stats.successNum + '个<br /><p style="font-size:22px; color:#0b8cec;font-weight: bold;">已上传成功,点击“下一步”吧</p>';
  248. }
  249. if ( stats.uploadFailNum ) {
  250. text += ',失败' + stats.uploadFailNum + '个';
  251. }
  252. }
  253. var txtSize=WebUploader.formatSize(fileSize);
  254. if(txtSize=="0B"){
  255. $("#upload-57c79f4938104 input[name='size']").val('');
  256. }
  257. else{
  258. $("#upload-57c79f4938104 input[name='size']").val(txtSize);
  259. }
  260. $info.html( text );
  261. }
  262. uploader.onUploadAccept=function(object ,ret){
  263. if(ret.error_info){
  264. fileError=ret.error_info;
  265. return false;
  266. }
  267. }
  268. uploader.onUploadSuccess=function(file ,response){
  269. fileName=response.filePath;
  270. filePixels=response.filePixels;
  271. }
  272. uploader.onUploadError=function(file){
  273. alert(fileError);
  274. }
  275. function setState( val ) {
  276. var file, stats;
  277. if ( val === state ) {
  278. return;
  279. }
  280. $upload.removeClass( 'state-' + state );
  281. $upload.addClass( 'state-' + val );
  282. state = val;
  283. switch ( state ) {
  284. case 'pedding':
  285. $placeHolder.removeClass( 'element-invisible' );
  286. $queue.parent().removeClass('filled');
  287. $queue.hide();
  288. $statusBar.addClass( 'element-invisible' );
  289. uploader.refresh();
  290. break;
  291. case 'ready':
  292. $placeHolder.addClass( 'element-invisible' );
  293. $( "#upload-57c79f4938104 .filePicker2" ).removeClass( 'element-invisible');
  294. $queue.parent().addClass('filled');
  295. $queue.show();
  296. $statusBar.removeClass('element-invisible');
  297. uploader.refresh();
  298. break;
  299. case 'uploading':
  300. $( "#upload-57c79f4938104 .filePicker2" ).addClass( 'element-invisible' );
  301. $progress.show();
  302. $upload.text( '暂停上传' );
  303. break;
  304. case 'paused':
  305. $progress.show();
  306. $upload.text( '继续上传' );
  307. break;
  308. case 'confirm':
  309. $progress.hide();
  310. $upload.text( '开始上传' ).addClass( 'disabled' );
  311. stats = uploader.getStats();
  312. if ( stats.successNum && !stats.uploadFailNum ) {
  313. setState( 'finish' );
  314. return;
  315. }
  316. break;
  317. case 'finish':
  318. stats = uploader.getStats();
  319. if ( stats.successNum ) {
  320. $("#upload-57c79f4938104 input[name='image']").val(fileName);
  321. if(filePixels=="*px"){
  322. $("#upload-57c79f4938104 input[name='pixels']").val();
  323. }
  324. else
  325. {
  326. $("#upload-57c79f4938104 input[name='pixels']").val(filePixels);
  327. }
  328. } else {
  329. // 没有成功的图片,重设
  330. state = 'done';
  331. location.reload();
  332. }
  333. break;
  334. }
  335. updateStatus();
  336. }
  337. uploader.onUploadProgress = function( file, percentage ) {
  338. var $li = $('#'+file.id),
  339. $percent = $li.find('.progress span');
  340. $percent.css( 'width', percentage * 100 + '%' );
  341. percentages[ file.id ][ 1 ] = percentage;
  342. updateTotalProgress();
  343. };
  344. uploader.onFileQueued = function( file ) {
  345. fileCount++;
  346. fileSize += file.size;
  347. if ( fileCount === 1 ) {
  348. $placeHolder.addClass( 'element-invisible' );
  349. $statusBar.show();
  350. }
  351. addFile( file );
  352. setState( 'ready' );
  353. updateTotalProgress();
  354. };
  355. uploader.onFileDequeued = function( file ) {
  356. fileCount--;
  357. fileSize -= file.size;
  358. if ( !fileCount ) {
  359. setState( 'pedding' );
  360. }
  361. removeFile( file );
  362. updateTotalProgress();
  363. };
  364. uploader.on( 'all', function( type ) {
  365. var stats;
  366. switch( type ) {
  367. case 'uploadFinished':
  368. setState( 'confirm' );
  369. break;
  370. case 'startUpload':
  371. setState( 'uploading' );
  372. break;
  373. case 'stopUpload':
  374. setState( 'paused' );
  375. break;
  376. }
  377. });
  378. uploader.onError = function( code ) {
  379. alert( 'Eroor: ' + code );
  380. };
  381. $upload.on('click', function() {
  382. if ( $(this).hasClass( 'disabled' ) ) {
  383. return false;
  384. }
  385. if ( state === 'ready' ) {
  386. uploader.upload();
  387. } else if ( state === 'paused' ) {
  388. uploader.upload();
  389. } else if ( state === 'uploading' ) {
  390. uploader.stop();
  391. }
  392. });
  393. $info.on( 'click', '.retry', function() {
  394. uploader.retry();
  395. } );
  396. $info.on( 'click', '.ignore', function() {
  397. alert( 'todo' );
  398. } );
  399. $upload.addClass( 'state-' + state );
  400. updateTotalProgress();
  401. });
  402. /*上传文件操作  结束*/
  403. </script>
  404. <script>
  405. var BASE_URL = '__PUBLIC__/webuploader';
  406. </script>
  407. <script src="__PUBLIC__/webuploader/webuploader.min.js"></script>
  408. </body>
  409. </html>
    1. php:MafullController.class.php中写入上传方法:
    2. /**
    3. * webuploader 上传demo
    4. */
    5. public function webuploader(){
    6. // 如果是post提交则显示上传的文件 否则显示上传页面
    7. if(IS_POST){
    8. $image=I('post.image');
    9. // 判断是否有文件上传
    10. if (empty($image)) {
    11. die('没有上传文件');
    12. }
    13. echo '上传成功路径为:'.$image;
    14. }else{
    15. $this->display();
    16. }
    17. }
    18. //切片上传方法
    19. public function ajax_upload()
    20. {
    21. //故意写一个过期时间目的也是让浏览器去重新读取页面内容.你要知道,浏览器一般情况下去保存你访问过的页面的大部分内容,你第二次访问的时候,保存的内容(称为缓存)浏览器就不需要再向服务器请求了,这样节约时间,也减轻了服务器的负担.
    22. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");//内容过期时间
    23. header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");//标记内容最后修改时间
    24. header("Cache-Control: no-store, no-cache, must-revalidate");//强制不缓存
    25. header("Cache-Control: post-check=0, pre-check=0", false);//Internet Explorer 5对于HTTP头信息使用两种新的时间间隔指示
    26. header("Pragma: no-cache");//禁止本页被缓存
    27. //$_SERVER['REQUEST_METHOD']这个变量表示的是表单提交数据的方式,get或者post
    28. if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    29. exit; // 完成预检CORS请求
    30. }
    31. if ( !empty($_REQUEST[ 'debug' ]) ) {
    32. $random = rand(0, intval($_REQUEST[ 'debug' ]) );
    33. if ( $random === 0 ) {
    34. header("HTTP/1.0 500 Internal Server Error");
    35. exit;
    36. }
    37. }
    38. // 5分钟执行时间
    39. @set_time_limit(5 * 60);
    40. $targetDir = 'Public\Upload'.DIRECTORY_SEPARATOR.'file_material_tmp';
    41. $uploadDir = 'Public\Upload'.DIRECTORY_SEPARATOR.'file_material';
    42. $cleanupTargetDir = true; // 是否删除以前的临时文件内容
    43. $maxFileAge = 5 * 3600; // 临时文件时间(以秒为单位)
    44. // 获取文件名
    45. if (!file_exists($targetDir)) {
    46. @mkdir($targetDir);//mkdir() 函数创建目录。
    47. }
    48. // 创建目标目录
    49. if (!file_exists($uploadDir)) {
    50. @mkdir($uploadDir);//mkdir() 函数创建目录。
    51. }
    52. // 获取文件名
    53. if (isset($_REQUEST["name"])) {
    54. $fileName = $_REQUEST["name"];
    55. } elseif (!empty($_FILES)) {
    56. $fileName = $_FILES["file"]["name"];
    57. } else {
    58. $fileName = uniqid("file_");
    59. }
    60. $fileName=iconv("UTF-8", "gb2312", $fileName);
    61. $oldName = $fileName;
    62. $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
    63. // 取得chunk和chunks
    64. $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
    65. $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
    66. // 删除以前的临时文件内容,如:file_material_tmp文件夹内的文件
    67. if ($cleanupTargetDir) {
    68. if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
    69. //is_dir -- 判断给定文件名是否是一个目录
    70. //opendir()函数的作用是:打开目录句柄。
    71. die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
    72. }
    73. while (($file = readdir($dir)) !== false) {//readdir ,readdir_r,----读一个目录
    74. $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
    75. // 如果临时文件是当前文件,继续下一步
    76. if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
    77. continue;
    78. }
    79. // 删除临时文件,如果它早于最大年龄,并且不是当前文件
    80. //preg_match() 函数用于进行正则表达式匹配,成功返回 1 ,否则返回 0
    81. if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
    82. //filemtime() 函数返回文件内容上次的修改时间。若成功,则时间以 Unix 时间戳的方式返回。若失败,则返回 false。
    83. @unlink($tmpfilePath);//unlink() 函数删除文件。
    84. }
    85. }
    86. closedir($dir);
    87. }
    88. // 打开临时文件
    89. if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
    90. die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
    91. }
    92. if (!empty($_FILES)) {
    93. if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
    94. die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
    95. }
    96. // 读取二进制输入流并将其附加到临时文件
    97. if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
    98. die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
    99. }
    100. } else {
    101. if (!$in = @fopen("php://input", "rb")) {
    102. die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
    103. }
    104. }
    105. while ($buff = fread($in, 4096)) {
    106. fwrite($out, $buff);
    107. }
    108. @fclose($out);
    109. @fclose($in);
    110. rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
    111. $index = 0;
    112. $done = true;
    113. for( $index = 0; $index < $chunks; $index++ ) {
    114. if ( !file_exists("{$filePath}_{$index}.part") ) {
    115. $done = false;
    116. break;
    117. }
    118. }
    119. if ( $done ) {
    120. $pathInfo = pathinfo($fileName);
    121. $hashStr = substr(md5($pathInfo['basename']),8,16);
    122. $hashName = time() . $hashStr . '.' .$pathInfo['extension'];
    123. $uploadPath = $uploadDir . DIRECTORY_SEPARATOR .$hashName;
    124. if (!$out = @fopen($uploadPath, "wb")) {
    125. die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
    126. }
    127. if ( flock($out, LOCK_EX) ) {
    128. for( $index = 0; $index < $chunks; $index++ ) {
    129. if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
    130. break;
    131. }
    132. while ($buff = fread($in, 4096)) {
    133. fwrite($out, $buff);
    134. }
    135. @fclose($in);
    136. @unlink("{$filePath}_{$index}.part");
    137. }
    138. flock($out, LOCK_UN);
    139. }
    140. @fclose($out);
    141. //$data=array();
    142. //$data['name']=$uploadPath;//Public\Upload\file_material\14793553561ee00a15b8a23204.jpg
    143. //echo json_encode($data);`
    144. //exit;
    145. //$data['name']=trim($uploadPath);
    146. $list = getimagesize($uploadPath);
    147. $data['pixels']=trim($list[0]."*".$list[1].'px');
    148. $response = array(
    149. 'success'=>true,
    150. 'oldName'=>$oldName,
    151. 'filePath'=>trim(str_replace("\\","/",substr($uploadPath,6))),
    152. 'fileSize'=>$data['size'],
    153. 'fileSuffixes'=>$pathInfo['extension'],
    154. 'file_id'=>$data['id'],
    155. 'filePixels'=>$data['pixels'],
    156. );
    157. die(json_encode($response));
    158. }
    159. // 返回成功JSON-RPC响应
    160. die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
    161. }
上一篇:蓝桥杯 历届试题 约数倍数选卡片 (经典数论+DFS)


下一篇:Xshell拖拽上传文件插件