Thinkphp5+plupload图片上传功能,支持实时预览图片。
今天和大家分享一个国外的图片上传插件,这个插件支持分片上传大文件。其中著名的七牛云平台的jssdk就使用了puupload插件,可见这个插件还是相当牛叉的。
这个插件不仅仅支持图片上传,还支持大多数文件的上传,例如视频文件,音频文件,word文件等等,而且大文件都采用分片上传的机制。
Plupload有以下功能和特点:
1、拥有多种上传方式:HTML5、flash、silverlight以及传统的<input type=”file” />。Plupload会自动侦测当前的环境,选择最合适的上传方式,并且会优先使用HTML5的方式。所以你完全不用去操心当前的浏览器支持哪些上传方式,Plupload会自动为你选择最合适的方式。
2、支持以拖拽的方式来选取要上传的文件
3、支持在前端压缩图片,即在图片文件还未上传之前就对它进行压缩
4、可以直接读取原生的文件数据,这样的好处就是例如可以在图片文件还未上传之前就能把它显示在页面上预览
5、支持把大文件切割成小片进行上传,因为有些浏览器对很大的文件比如几G的一些文件无法上传。
下面就介绍一个tp5整合plupload图片上传插件的小案例,希望给大家带来一点小帮助。
一、案例目录结构#
二、Index.php控制器方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php namespace app\index\controller; use think\Controller; use think\Db; class Index extends Controller{ public function index(){ $rootUrl = $this ->request->root(true); //ROOT域名 $rootUrl = explode ( 'index.php' , $rootUrl )[0]; //模板资源变量分配 foreach (config( 'TMPL_PARSE_STRING' ) as $key => $value ) { $this ->view->assign( '_' . $key , $rootUrl . $value ); } return $this ->fetch(); } //图片上传方法 public function upload_images(){ if ( $this ->request->isPost()){ //接收参数 $images = $this ->request->file( 'file' ); //计算md5和sha1散列值,TODO::作用避免文件重复上传 $md5 = $images ->hash( 'md5' ); $sha1 = $images ->hash( 'sha1' ); //判断图片文件是否已经上传 $img = Db::name( 'picture' )->where([ 'md5' => $md5 , 'sha1' => $sha1 ])->find(); //我这里是将图片存入数据库,防止重复上传 if (! empty ( $img )){ return json([ 'status' =>1, 'msg' => '上传成功' , 'data' =>[ 'img_id' => $img [ 'id' ], 'img_url' => $this ->request->root(true). '/' . $img [ 'path' ]]]); } else { // 移动到框架应用根目录/public/uploads/picture/目录下 $imgPath = 'public' . DS . 'uploads' . DS . 'picture' ; $info = $images ->move(ROOT_PATH . $imgPath ); $path = 'public/uploads/picture/' . date ( 'Ymd' ,time()). '/' . $info ->getFilename(); $data = [ 'path' => $path , 'md5' => $md5 , 'sha1' => $sha1 , 'status' => 1 , 'create_time' => time() , ]; if ( $img_id =Db::name( 'picture' )->insertGetId( $data )){ return json([ 'status' =>1, 'msg' => '上传成功' , 'data' =>[ 'img_id' => $img_id , 'img_url' => $this ->request->root(true). '/' . $path ]]); } else { return json([ 'status' =>0, 'msg' => '写入数据库失败' ]); } } } else { return [ 'status' =>0, 'msg' => '非法请求!' ]; } } } |
三、index.html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>tp5+plupload图片上传</title> </head> <body> <!-- production --> <!--<script type= "text/javascript" src= "./plupload.full.min.js" ></script>--> <!-- debug--> <script type= "text/javascript" src= "{$_plupload}/moxie.js" ></script> <script type= "text/javascript" src= "{$_plupload}/plupload.dev.js" ></script> <script type= "text/javascript" src= "{$_plupload}/jquery.min.js" ></script> <style> ul{ list-style:none; } #file-list {overflow: hidden;padding-left: initial;} #file-list li { width:160px; float: left; height:200px; position: relative; height: inherit; margin-bottom: inherit; } #file-list li a { width:150px; height:150px; text-align: center; display: flex; align-items: center; justify-content: center; margin:0 auto; border:1px solid #ccc; padding: 5px 5px 5px 5px; } .close{ background-image: url( "{$_plupload}/close.png" ); width: 30px; height: 30px; background-size: contain; position: absolute; right: 2%; top: 0; } #file-list li a img {max-width:100%;max-height: 100%;} .progress{ position: absolute; background-color: rgba(4, 4, 4, 0.53); color: #fff; padding: 3px 3px 3px 3px; border-radius: 10%; } </style> <input type= "hidden" id= "images_upload" name= "images" value= "" /> <div id= "container" > <button class = "btn btn-primary" type= "button" id= "pickfiles" style= "height: 30px;line-height: 8px;" >选择图片</button> <button class = "btn btn-primary" type= "button" id= "uploadfiles" style= "display: none" >开始上传</button> <ul id= "file-list" > </ul> </div> <script type= "text/javascript" > //调用例子 var uploader = new plupload.Uploader({ runtimes : 'html5,flash,silverlight,html4' , //上传方式顺序优先级 browse_button : 'pickfiles' , //选择图片按钮id container: document.getElementById( 'container' ), //容器 url : "{:url('Index/upload_images')}" , //服务器接口地址 flash_swf_url : "{$_plupload}/Moxie.swf" , silverlight_xap_url : "{$_plupload}/Moxie.xap" , multi_selection: true, //false为单图上传,true为多图上传 filters : { max_file_size : '100mb' , //限制文件上传大小 mime_types: [ {title : "Image files" , extensions : "jpg,gif,png" }, //限制文件上传格式 ] }, init: { //init事件发生后触发 PostInit: function () { //document.getElementById('filelist').innerHTML = ''; document.getElementById( 'uploadfiles' ).onclick = function () { uploader.start(); return false; }; }, FilesAdded: function (up, files) { //文件选择之后的触发的方法 var len = len = files.length; for ( var i = 0; i<len; i++){ var file_name = files[i].name; //文件名 var file_size = files[i].size; //文件大小 //构造html来更新UI //var html = '<li id="file-' + files[i].id +'"><p class="file-name">' + file_name + '(' + plupload.formatSize(file_size) + ')' + '</p><p class="progress"></p></li>'; var html = '<li id="file-' + files[i].id + '"><span class="close"></span></li>' ; $(html).appendTo( '#file-list' ); ! function (i){ previewImage(files[i], function (imgsrc){ $( '#file-' +files[i].id).append( '<a><img src="' + imgsrc + '" /><span class="progress">12</span></a>' ); }) }(i); $( "#uploadfiles" ).trigger( 'click' ); } /*plupload.each(files, function(file) { document.getElementById('filelist').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ') <b></b></div>'; });*/ }, UploadProgress: function (up, file) { //上传过程中调用的方法 //document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>"; $( '#file-' +file.id + " .progress" ).html(file.percent + "%" ); }, FileUploaded : function (up,file,res) { //文件上传完成后 console.log(res.response); var data = JSON.parse(res.response).data; $( '#file-' +file.id).children( '.close' ).attr( 'img_id' ,data.img_id); var img = $( "#images_upload" ); var str = img.val(); if (str == '' ){ str = data.img_id; } else { str += ',' +data.img_id; } img.val(str); }, Error: function (up, err) { //document.getElementById('console').appendChild(document.createTextNode("\nError #" + err.code + ": " + err.message)); } } }); //plupload中为我们提供了mOxie对象 //有关mOxie的介绍和说明请看:https://github.com/moxiecode/moxie/wiki/API //file为plupload事件监听函数参数中的file对象,callback为预览图片准备完成的回调函数 function previewImage(file,callback){ if (!file || !/image\ //.test(file.type)) return; //确保文件是图片 if (file.type== 'image/gif' ){ //gif使用FileReader进行预览,因为mOxie.Image只支持jpg和png var gif = new moxie.file.FileReader(); gif.onload = function (){ callback(gif.result); gif.destroy(); gif = null; }; gif.readAsDataURL(file.getSource()); } else { var image = new moxie.image.Image(); image.onload = function () { image.downsize( 150, 150 ); //先压缩一下要预览的图片,宽300,高300 var imgsrc = image.type== 'image/jpeg' ? image.getAsDataURL( 'image/jpeg' ,80) : image.getAsDataURL(); //得到图片src,实质为一个base64编码的数据 callback && callback(imgsrc); //callback传入的参数为预览图片的url image.destroy(); image = null; }; image.load( file.getSource() ); } } uploader.init(); //移除图片 $( "#file-list" ).on( 'click' , ".close" , function (){ var img_id = $(this).attr( "img_id" ); var img = $( "#images_upload" ); var items=img.val().split( "," ); var index = items.indexOf(img_id); items.splice(index,1); //删除元素 img.val(items.join( ',' )); $(this).parent().remove(); }); </script> </body> </html> |
如果想研究插件源码的朋友,可以看这个文件,其中大部分都已经注释了。
最终效果就是这样了。
如果对tp5不太熟悉的朋友,建议直接配置虚拟域名,将项目目录绑定到/tp5/public/目录。
案例源码:https://github.com/BlueSimle/thinkphp5-plupload (如果对你有帮助,请给个star哦。如果有什么疑问,请留言)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2015-08-21 模拟登录学校教务管理系统,获取成绩单!
2015-08-21 PHP中正则表达式学习及应用(四)
2015-08-21 各大牛逼讲师的经典Jquery精品视频教程,大放送啦!!!(包括手机移动端JqueryWeb开发)!!!
2015-08-21 PHP中正则表达式学习及应用(三)