
本文介绍一个采用HTML5 API的web应用—上传中心(Upload Center),允许用户从本地计算机中拖拽图片到浏览器窗口上传图片。有图片预览和上传进度条,这些都可由客户端来控制。上传后,这些图片只是被存储到服务器上了,接下来就可以随意引用了。
什么是HTML5 文件上传
上传文件运用了HTML5的三个新特性:1、新的文件读取api(File Reader API) 2、新的拖拽api(Drag & Drop API) 3、新的IO-ajax(增加了二进制数据传输)。下面是HTML5文件上传的步骤:
- 1、用户从本地计选择一个或多个文件拖拽到浏览器窗口。支持拖拽的的浏览器会触发一个事件,事件包括一些有用的信息,其中包涵被选中的文件信息。
- 2、用HTML5的文件读取api,以二进制数据读取被选文件,并存储到内存中。
- 3、用XMLHttpRequest对象的新方法-sendAsBinary,将数据传到服务器。
jQuery插件— Filedrop已经封装好这些功能,并且提供配置接口来限制上传文件的大小和指定回调函数。非常方便运用到自己的应用中。
目前来看,文件上传只能在firefox和chrome浏览器中使用,但其他主流浏览器的下个版本已经计划支持该功能了。当然对于不支持的浏览器可以简单的放置input file控件来代替。但本文重点是应用HTML5上,这里就不做处理了。
现在开始,首先是HTML结构
上传中心的Html结构比较简单。先声明HTML5的doctype,然后引入样式文件和脚本文件-script.js、filedrop插件脚本和jquery库。
html结构如下:
index.html
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <title>HTML5 File Drag and Drop Upload with jQuery and PHP | Tutorialzine Demo</title>
- <!-- Our CSS stylesheet file -->
- <link rel="stylesheet" href="assets/css/styles.css" />
- <!--[if lt IE 9]>
- <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
- <![endif]-->
- </head>
- <body>
- <header>
- <h1>HTML5 File Upload with jQuery and PHP</h1>
- </header>
- <div id="dropbox">
- <span class="message">Drop images here to upload. <br /><i>(they will only be visible to you)</i></span>
- </div>
- <!-- Including The jQuery Library -->
- <script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
- <!-- Including the HTML5 Uploader plugin -->
- <script src="assets/js/jquery.filedrop.js"></script>
- <!-- The main script file -->
- <script src="assets/js/script.js"></script>
- </body>
- </html>
这里div#dropbox会传递给filedrop插件,插件会监听是否有文件被拖拽到div#dropbox上。当上传出错时,展现信息的span会提示错误信息。(如,浏览器不支持HTML5的api时就会显示相应的提示信息)
然后,文件选择后,通过基于jquery的js编码实现图片预览效果。预览html结构如下:
- <div class="preview done">
- <span class="imageHolder">
- <img src="" />
- <span class="uploaded"></span>
- </span>
- <div class="progressHolder">
- <div class="progress"></div>
- </div>
- </div>
本段包括图片预览(img 的src属性会用图片的DataURL填充)和上传进度条的html结构。预览容器的一个class值done,可以使span.uploaded显示(默认情况下该span是隐藏的)。该span用绿色背景标记,表示上传已完成。
html结构完成了,接下来开始脚本编码。
事实上文件上传相关的功能Filedrop插件都封装好了,这里的上传中心只需要运用它,并且将回调的方法传递给它。需要在服务器端写一段php脚本来处理上传的文件,下面一节会讲到。
第一步,写一个辅助的方法来读取文件对象(该对象是文件被选择后由浏览器端创建的,包括如文件名称、文件路劲和文件大小等的属性),然后生成预览的html结构。
assets/js/script.js
- var template = '<div class="preview">'+
- '<span class="imageHolder">'+
- '<img />'+
- '<span class="uploaded"></span>'+
- '</span>'+
- '<div class="progressHolder">'+
- '<div class="progress"></div>'+
- '</div>'+
- '</div>';
- function createImage(file){
- var preview = $(template),
- image = $('img', preview);
- var reader = new FileReader();
- image.width = 100;
- image.height = 100;
- reader.onload = function(e){
- // e.target.result holds the DataURL which
- // can be used as a source of the image:
- image.attr('src',e.target.result);
- };
- // Reading the file as a DataURL. When finished,
- // this will trigger the onload function above:
- reader.readAsDataURL(file);
- message.hide();
- preview.appendTo(dropbox);
- // Associating a preview container
- // with the file, using jQuery's $.data():
- $.data(file,preview);
- }
Template用于创建图片预览的HTML结构。获取图片的DataURL(64位编码的图片数据),然后赋值给图片的src。然后创建好的预览会被添加到div#dropbox中。现在还剩下filedrop的回调处理了。
assets/js/script.js
- $(function(){
- var dropbox = $('#dropbox'),
- message = $('.message', dropbox);
- dropbox.filedrop({
- // The name of the $_FILES entry:
- paramname:'pic',
- maxfiles: 5,
- maxfilesize: 2, // in mb
- url: 'post_file.php',
- uploadFinished:function(i,file,response){
- $.data(file).addClass('done');
- // response is the JSON object that post_file.php returns
- },
- error: function(err, file) {
- switch(err) {
- case 'BrowserNotSupported':
- showMessage('Your browser does not support HTML5 file uploads!');
- break;
- case 'TooManyFiles':
- alert('Too many files! Please select 5 at most!');
- break;
- case 'FileTooLarge':
- alert(file.name+' is too large! Please upload files up to 2mb.');
- break;
- default:
- break;
- }
- },
- // Called before each upload is started
- beforeEach: function(file){
- if(!file.type.match(/^image\//)){
- alert('Only images are allowed!');
- // Returning false will cause the
- // file to be rejected
- return false;
- }
- },
- uploadStarted:function(i, file, len){
- createImage(file);
- },
- progressUpdated: function(i, file, progress) {
- $.data(file).find('.progress').width(progress);
- }
- });
- var template = '...';
- function createImage(file){
- // ... see above ...
- }
- function showMessage(msg){
- message.html(msg);
- }
- });
然后,被拖拽到div#dropbox的有效的图片文件通过post_file.php上传到服务器上。
PHP 处理:
在php服务器端,正常上传的图片和被拖拽上传的图片不会有区别。这意味着在服务器端只需要提供一个回调来处理上传的文件。
post_file.php
- // If you want to ignore the uploaded files,
- // set $demo_mode to true;
- $demo_mode = false;
- $upload_dir = 'uploads/';
- $allowed_ext = array('jpg','jpeg','png','gif');
- if(strtolower($_SERVER['REQUEST_METHOD']) != 'post'){
- exit_status('Error! Wrong HTTP method!');
- }
- if(array_key_exists('pic',$_FILES) && $_FILES['pic']['error'] == 0 ){
- $pic = $_FILES['pic'];
- if(!in_array(get_extension($pic['name']),$allowed_ext)){
- exit_status('Only '.implode(',',$allowed_ext).' files are allowed!');
- }
- if($demo_mode){
- // File uploads are ignored. We only log them.
- $line = implode(' ', array( date('r'), $_SERVER['REMOTE_ADDR'],$pic['size'], $pic['name']));
- file_put_contents('log.txt', $line.PHP_EOL, FILE_APPEND);
- exit_status('Uploads are ignored in demo mode.');
- }
- // Move the uploaded file from the temporary
- // directory to the uploads folder:
- if(move_uploaded_file($pic['tmp_name'], $upload_dir.$pic['name'])){
- exit_status('File was uploaded successfuly!');
- }
- }
- exit_status('Something went wrong with your upload!');
- // Helper functions
- function exit_status($str){
- echo json_encode(array('status'=>$str));
- exit;
- }
- function get_extension($file_name){
- $ext = explode('.', $file_name);
- $ext = array_pop($ext);
- return strtolower($ext);
- }
该段脚本执行监听http请求和验证上传的文件。(如果php脚本中不使用move_upload_file()方法上传文件,那么文件将自动在请求结束后予以删除。)
最后,给上传中心添加样式。
下面列出部分样式,一些与上传不相关的没有这里没有列出来。如果想看完整的样式,可以查看style.css
assets/css/styles.css
- /*-------------------------
- Dropbox Element
- --------------------------*/
- #dropbox{
- background:url('../img/background_tile_3.jpg');
- border-radius:3px;
- position: relative;
- margin:80px auto 90px;
- min-height: 290px;
- overflow: hidden;
- padding-bottom: 40px;
- width: 990px;
- box-shadow:0 0 4px rgba(0,0,0,0.3) inset,0 -3px 2px rgba(0,0,0,0.1);
- }
- #dropbox .message{
- font-size: 11px;
- text-align: center;
- padding-top:160px;
- display: block;
- }
- #dropbox .message i{
- color:#ccc;
- font-size:10px;
- }
- #dropbox:before{
- border-radius:3px 3px 0 0;
- }
- /*-------------------------
- Image Previews
- --------------------------*/
- #dropbox .preview{
- width:245px;
- height: 215px;
- float:left;
- margin: 55px 0 0 60px;
- position: relative;
- text-align: center;
- }
- #dropbox .preview img{
- max-width: 240px;
- max-height:180px;
- border:3px solid #fff;
- display: block;
- box-shadow:0 0 2px #000;
- }
- #dropbox .imageHolder{
- display: inline-block;
- position:relative;
- }
- #dropbox .uploaded{
- position: absolute;
- top:0;
- left:0;
- height:100%;
- width:100%;
- background: url('../img/done.png') no-repeat center centerrgba(255,255,255,0.5);
- display: none;
- }
- #dropbox .preview.done .uploaded{
- display: block;
- }
- /*-------------------------
- Progress Bars
- --------------------------*/
- #dropbox .progressHolder{
- position: absolute;
- background-color:#252f38;
- height:12px;
- width:100%;
- left:0;
- bottom: 0;
- box-shadow:0 0 2px #000;
- }
- #dropbox .progress{
- background-color:#2586d0;
- position: absolute;
- height:100%;
- left:0;
- width:0;
- box-shadow: 0 0 1px rgba(255, 255, 255, 0.4) inset;
- -moz-transition:0.25s;
- -webkit-transition:0.25s;
- -o-transition:0.25s;
- transition:0.25s;
- }
- #dropbox .preview.done .progress{
- width:100% !important;
- }
Div.progress绝对定位。改变它的width(百分数值)来做进度条的显示。这里可以应用jquery实现动画效果。
到这里,HTML5的上传中心完成了。可以将它运用到文件上传服务、html5画廊、文件管理或别的新应用中。记得留下你的建议和意见!

顶下
留着备用
createImage()函数中如果reader.onload 失败会如何呢
效果很不错。但不是太会用。
好牛B的效果