• Jquery AjaxUpload实现文件上传


    以下是本人实现ajax上传图片时参考的文章,希望能对大家有帮助。

    在PHP网站开发中,文件上传功能时常用到,之前我已介绍过如何利用PHP实现文件上传功能。随着WEB技术的发展,用户体验成为衡量网站成功与否的关键,今天和大家分享如何在PHP中利用Jquery实现Ajax方式文件上传功能的例子,其中使用到了Jquery插件Ajaxupload,其可以实现单个文件和多文件上传功能。

    AjaxUpload

      Jquery插件AjaxUpload实现文件上传功能时无需创建form表单,即可实现Ajax方式的文件上传,当然根据需要也可以创建form表单。

    准备工作

    1、下载Jquery开发包和文件上传插件AjaxUpload

    ajaxupload.3.5.js  文件源码:

    /**
     * Ajax upload
     * Project page - http://valums.com/ajax-upload/
     * Copyright (c) 2008 Andris Valums, http://valums.com
     * Licensed under the MIT license (http://valums.com/mit-license/)
     * Version 3.5 (23.06.2009)
     */

    /**
     * Changes from the previous version:
     * 1. Added better JSON handling that allows to use 'application/javascript' as a response
     * 2. Added demo for usage with jQuery UI dialog
     * 3. Fixed IE "mixed content" issue when used with secure connections
     *
     * For the full changelog please visit:
     * http://valums.com/ajax-upload-changelog/
     */

    (function(){
        
    var d = document, w = window;

    /**
     * Get element by id
     */    
    function get(element){
        if (typeof element == "string")
            element = d.getElementById(element);
        return element;
    }

    /**
     * Attaches event to a dom element
     */
    function addEvent(el, type, fn){
        if (w.addEventListener){
            el.addEventListener(type, fn, false);
        } else if (w.attachEvent){
            var f = function(){
              fn.call(el, w.event);
            };            
            el.attachEvent('on' + type, f)
        }
    }


    /**
     * Creates and returns element from html chunk
     */
    var toElement = function(){
        var div = d.createElement('div');
        return function(html){
            div.innerHTML = html;
            var el = div.childNodes[0];
            div.removeChild(el);
            return el;
        }
    }();

    function hasClass(ele,cls){
        return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
    }
    function addClass(ele,cls) {
        if (!hasClass(ele,cls)) ele.className += " "+cls;
    }
    function removeClass(ele,cls) {
        var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
        ele.className=ele.className.replace(reg,' ');
    }

    // getOffset function copied from jQuery lib (http://jquery.com/)
    if (document.documentElement["getBoundingClientRect"]){
        // Get Offset using getBoundingClientRect
        // http://ejohn.org/blog/getboundingclientrect-is-awesome/
        var getOffset = function(el){
            var box = el.getBoundingClientRect(),
            doc = el.ownerDocument,
            body = doc.body,
            docElem = doc.documentElement,
            
            // for ie
            clientTop = docElem.clientTop || body.clientTop || 0,
            clientLeft = docElem.clientLeft || body.clientLeft || 0,
            
            // In Internet Explorer 7 getBoundingClientRect property is treated as physical,
            // while others are logical. Make all logical, like in IE8.
            
            
            zoom = 1;
            if (body.getBoundingClientRect) {
                var bound = body.getBoundingClientRect();
                zoom = (bound.right - bound.left)/body.clientWidth;
            }
            if (zoom > 1){
                clientTop = 0;
                clientLeft = 0;
            }
            var top = box.top/zoom + (window.pageYOffset || docElem && docElem.scrollTop/zoom || body.scrollTop/zoom) - clientTop,
            left = box.left/zoom + (window.pageXOffset|| docElem && docElem.scrollLeft/zoom || body.scrollLeft/zoom) - clientLeft;
                    
            return {
                top: top,
                left: left
            };
        }
        
    } else {
        // Get offset adding all offsets
        var getOffset = function(el){
            if (w.jQuery){
                return jQuery(el).offset();
            }        
                
            var top = 0, left = 0;
            do {
                top += el.offsetTop || 0;
                left += el.offsetLeft || 0;
            }
            while (el = el.offsetParent);
            
            return {
                left: left,
                top: top
            };
        }
    }

    function getBox(el){
        var left, right, top, bottom;    
        var offset = getOffset(el);
        left = offset.left;
        top = offset.top;
                            
        right = left + el.offsetWidth;
        bottom = top + el.offsetHeight;        
            
        return {
            left: left,
            right: right,
            top: top,
            bottom: bottom
        };
    }

    /**
     * Crossbrowser mouse coordinates
     */
    function getMouseCoords(e){        
        // pageX/Y is not supported in IE
        // http://www.quirksmode.org/dom/w3c_cssom.html            
        if (!e.pageX && e.clientX){
            // In Internet Explorer 7 some properties (mouse coordinates) are treated as physical,
            // while others are logical (offset).
            var zoom = 1;    
            var body = document.body;
            
            if (body.getBoundingClientRect) {
                var bound = body.getBoundingClientRect();
                zoom = (bound.right - bound.left)/body.clientWidth;
            }

            return {
                x: e.clientX / zoom + d.body.scrollLeft + d.documentElement.scrollLeft,
                y: e.clientY / zoom + d.body.scrollTop + d.documentElement.scrollTop
            };
        }
        
        return {
            x: e.pageX,
            y: e.pageY
        };        

    }
    /**
     * Function generates unique id
     */        
    var getUID = function(){
        var id = 0;
        return function(){
            return 'ValumsAjaxUpload' + id++;
        }
    }();

    function fileFromPath(file){
        return file.replace(/.*(\/|\\)/, "");            
    }

    function getExt(file){
        return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
    }            

    // Please use AjaxUpload , Ajax_upload will be removed in the next version
    Ajax_upload = AjaxUpload = function(button, options){
        if (button.jquery){
            // jquery object was passed
            button = button[0];
        } else if (typeof button == "string" && /^#.*/.test(button)){                    
            button = button.slice(1);                
        }
        button = get(button);    
        
        this._input = null;
        this._button = button;
        this._disabled = false;
        this._submitting = false;
        // Variable changes to true if the button was clicked
        // 3 seconds ago (requred to fix Safari on Mac error)
        this._justClicked = false;
        this._parentDialog = d.body;
        
        if (window.jQuery && jQuery.ui && jQuery.ui.dialog){
            var parentDialog = jQuery(this._button).parents('.ui-dialog');
            if (parentDialog.length){
                this._parentDialog = parentDialog[0];
            }
        }            
                        
        this._settings = {
            // Location of the server-side upload script
            action: 'upload.php',            
            // File upload name
            name: 'userfile',
            // Additional data to send
            data: {},
            // Submit file as soon as it's selected
            autoSubmit: true,
            // The type of data that you're expecting back from the server.
            // Html and xml are detected automatically.
            // Only useful when you are using json data as a response.
            // Set to "json" in that case.
            responseType: false,
            // When user selects a file, useful with autoSubmit disabled            
            onChange: function(file, extension){},                    
            // Callback to fire before file is uploaded
            // You can return false to cancel upload
            onSubmit: function(file, extension){},
            // Fired when file upload is completed
            // WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!
            onComplete: function(file, response) {}
        };

        // Merge the users options with our defaults
        for (var i in options) {
            this._settings[i] = options[i];
        }
        
        this._createInput();
        this._rerouteClicks();
    }
                
    // assigning methods to our class
    AjaxUpload.prototype = {
        setData : function(data){
            this._settings.data = data;
        },
        disable : function(){
            this._disabled = true;
        },
        enable : function(){
            this._disabled = false;
        },
        // removes ajaxupload
        destroy : function(){
            if(this._input){
                if(this._input.parentNode){
                    this._input.parentNode.removeChild(this._input);
                }
                this._input = null;
            }
        },                
        /**
         * Creates invisible file input above the button
         */
        _createInput : function(){
            var self = this;
            var input = d.createElement("input");
            input.setAttribute('type', 'file');
            input.setAttribute('name', this._settings.name);
            var styles = {
                'position' : 'absolute'
                ,'margin': '-5px 0 0 -175px'
                ,'padding': 0
                ,'width': '220px'
                ,'height': '30px'
                ,'fontSize': '14px'                                
                ,'opacity': 0
                ,'cursor': 'pointer'
                ,'display' : 'none'
                ,'zIndex' :  2147483583 //Max zIndex supported by Opera 9.0-9.2x
                // Strange, I expected 2147483647                    
            };
            for (var i in styles){
                input.style[i] = styles[i];
            }
            
            // Make sure that element opacity exists
            // (IE uses filter instead)
            if ( ! (input.style.opacity === "0")){
                input.style.filter = "alpha(opacity=0)";
            }
                                
            this._parentDialog.appendChild(input);

            addEvent(input, 'change', function(){
                // get filename from input
                var file = fileFromPath(this.value);    
                if(self._settings.onChange.call(self, file, getExt(file)) == false ){
                    return;                
                }                                                        
                // Submit form when value is changed
                if (self._settings.autoSubmit){
                    self.submit();                        
                }                        
            });
            
            // Fixing problem with Safari
            // The problem is that if you leave input before the file select dialog opens
            // it does not upload the file.
            // As dialog opens slowly (it is a sheet dialog which takes some time to open)
            // there is some time while you can leave the button.
            // So we should not change display to none immediately
            addEvent(input, 'click', function(){
                self.justClicked = true;
                setTimeout(function(){
                    // we will wait 3 seconds for dialog to open
                    self.justClicked = false;
                }, 3000);            
            });        
            
            this._input = input;
        },
        _rerouteClicks : function (){
            var self = this;
        
            // IE displays 'access denied' error when using this method
            // other browsers just ignore click()
            // addEvent(this._button, 'click', function(e){
            //   self._input.click();
            // });
                    
            var box, dialogOffset = {top:0, left:0}, over = false;                            
            addEvent(self._button, 'mouseover', function(e){
                if (!self._input || over) return;
                over = true;
                box = getBox(self._button);
                        
                if (self._parentDialog != d.body){
                    dialogOffset = getOffset(self._parentDialog);
                }    
            });
            
        
            // we can't use mouseout on the button,
            // because invisible input is over it
            addEvent(document, 'mousemove', function(e){
                var input = self._input;            
                if (!input || !over) return;
                
                if (self._disabled){
                    removeClass(self._button, 'hover');
                    input.style.display = 'none';
                    return;
                }    
                                            
                var c = getMouseCoords(e);

                if ((c.x >= box.left) && (c.x <= box.right) &&
                (c.y >= box.top) && (c.y <= box.bottom)){            
                    input.style.top = c.y - dialogOffset.top + 'px';
                    input.style.left = c.x - dialogOffset.left + 'px';
                    input.style.display = 'block';
                    addClass(self._button, 'hover');                
                } else {        
                    // mouse left the button
                    over = false;
                    if (!self.justClicked){
                        input.style.display = 'none';
                    }
                    removeClass(self._button, 'hover');
                }            
            });            
                
        },
        /**
         * Creates iframe with unique name
         */
        _createIframe : function(){
            // unique name
            // We cannot use getTime, because it sometimes return
            // same value in safari :(
            var id = getUID();
            
            // Remove ie6 "This page contains both secure and nonsecure items" prompt
            // http://tinyurl.com/77w9wh
            var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />');
            iframe.id = id;
            iframe.style.display = 'none';
            d.body.appendChild(iframe);            
            return iframe;                        
        },
        /**
         * Upload file without refreshing the page
         */
        submit : function(){
            var self = this, settings = this._settings;    
                        
            if (this._input.value === ''){
                // there is no file
                return;
            }
                                            
            // get filename from input
            var file = fileFromPath(this._input.value);            

            // execute user event
            if (! (settings.onSubmit.call(this, file, getExt(file)) == false)) {
                // Create new iframe for this submission
                var iframe = this._createIframe();
                
                // Do not submit if user function returns false                                        
                var form = this._createForm(iframe);
                form.appendChild(this._input);
                
                form.submit();
                
                d.body.removeChild(form);                
                form = null;
                this._input = null;
                
                // create new input
                this._createInput();
                
                var toDeleteFlag = false;
                
                addEvent(iframe, 'load', function(e){
                        
                    if (// For Safari
                        iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" ||
                        // For FF, IE
                        iframe.src == "javascript:'<html></html>';"){                        
                        
                        // First time around, do not delete.
                        if( toDeleteFlag ){
                            // Fix busy state in FF3
                            setTimeout( function() {
                                d.body.removeChild(iframe);
                            }, 0);
                        }
                        return;
                    }                
                    
                    var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;

                    // fixing Opera 9.26
                    if (doc.readyState && doc.readyState != 'complete'){
                        // Opera fires load event multiple times
                        // Even when the DOM is not ready yet
                        // this fix should not affect other browsers
                        return;
                    }
                    
                    // fixing Opera 9.64
                    if (doc.body && doc.body.innerHTML == "false"){
                        // In Opera 9.64 event was fired second time
                        // when body.innerHTML changed from false
                        // to server response approx. after 1 sec
                        return;                
                    }
                    
                    var response;
                                        
                    if (doc.XMLDocument){
                        // response is a xml document IE property
                        response = doc.XMLDocument;
                    } else if (doc.body){
                        // response is html document or plain text
                        response = doc.body.innerHTML;
                        if (settings.responseType && settings.responseType.toLowerCase() == 'json'){
                            // If the document was sent as 'application/javascript' or
                            // 'text/javascript', then the browser wraps the text in a <pre>
                            // tag and performs html encoding on the contents.  In this case,
                            // we need to pull the original text content from the text node's
                            // nodeValue property to retrieve the unmangled content.
                            // Note that IE6 only understands text/html
                            if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE'){
                                response = doc.body.firstChild.firstChild.nodeValue;
                            }
                            if (response) {
                                response = window["eval"]("(" + response + ")");
                            } else {
                                response = {};
                            }
                        }
                    } else {
                        // response is a xml document
                        var response = doc;
                    }
                                                                                
                    settings.onComplete.call(self, file, response);
                            
                    // Reload blank page, so that reloading main page
                    // does not re-submit the post. Also, remember to
                    // delete the frame
                    toDeleteFlag = true;
                    
                    // Fix IE mixed content issue
                    iframe.src = "javascript:'<html></html>';";                                         
                });
        
            } else {
                // clear input to allow user to select same file
                // Doesn't work in IE6
                // this._input.value = '';
                d.body.removeChild(this._input);                
                this._input = null;
                
                // create new input
                this._createInput();                        
            }
        },        
        /**
         * Creates form, that will be submitted to iframe
         */
        _createForm : function(iframe){
            var settings = this._settings;
            
            // method, enctype must be specified here
            // because changing this attr on the fly is not allowed in IE 6/7        
            var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
            form.style.display = 'none';
            form.action = settings.action;
            form.target = iframe.name;
            d.body.appendChild(form);
            
            // Create hidden input element for each data key
            for (var prop in settings.data){
                var el = d.createElement("input");
                el.type = 'hidden';
                el.name = prop;
                el.value = settings.data[prop];
                form.appendChild(el);
            }            
            return form;
        }    
    };
    })();

    2、创建uploadfile.html,并引入Jquery开发包和AjaxUpload插件

    1
    2

    <script src="js/jquery-1.3.js"></script>
    <script src="js/ajaxupload.3.5.js"></script>

    3、根据Jquery插件AjaxUpload的需要,创建一个触发Ajax文件上传功能的DIV

    1
    2
    3
    4
    5
    6

    <ul>
        <li id="example">
        <div id="upload_button">文件上传</div>
        <p>已上传的文件列表:</p>
                <ol class="files"></ol>
    </ul>

    注释:由下面的代码我们可以看到Jquery插件AjaxUpload是根据upload_button这个DIV触发文件上传功能。 

    前台JS代码

      在代码中我设置了开关,根据需要可以匹配上传文件类型,同时也可以设置是以Ajax方式实现单个文件上传还是多个文件上传。

    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

    $(document).ready(function(){
        var button = $('#upload_button'), interval;
        var fileType = "all",fileNum = "one";
        new AjaxUpload(button,{
            action: 'do/uploadfile.php',
            /*data:{
                'buttoninfo':button.text()
            },*/
            name: 'userfile',
            onSubmit : function(file, ext){
                if(fileType == "pic")
                {
                    if (ext && /^(jpg|png|jpeg|gif)$/.test(ext)){
                        this.setData({
                            'info': '文件类型为图片'
                        });
                    } else {
                        $('<li></li>').appendTo('#example .files').text('非图片类型文件,请重传');
                        return false;              
                    }
                }
                           
                button.text('文件上传中');
               
                if(fileNum == 'one')
                    this.disable();
               
                interval = window.setInterval(function(){
                    var text = button.text();
                    if (text.length < 14){
                        button.text(text + '.');                   
                    } else {
                        button.text('文件上传中');            
                    }
                }, 200);
            },
            onComplete: function(file, response){
                if(response != "success")
                    alert(response);
                   
                button.text('文件上传');
                           
                window.clearInterval(interval);
                           
                this.enable();
               
                if(response == "success");
                    $('<li></li>').appendTo('#example .files').text(file);                 
            }
        });
     
    });

    注释
    第1行:$(document).ready()函数,Jquery中的函数,类似于window.load,使用这个函数可在DOM载入就绪能够读取并操纵时立即调用绑定的函数。

    第3行:fileType和fileNum参数代表上传文件的类型和数量,默认值为可上传所有类型文件,同一时间只能上传一个文件,如想上传图片文件或同时上传多个文件,可将这两个变量值变为pic和more。

    第6~8行:POST到服务器的数据,你可以设置静态值也可以通过Jquery的DOM操作函数获得一些动态值,比如form表单中INPUT的值等。

    第9行:等同于前端

    1

    <input type="file" name="userfile">

    服务器端$_FILES['userfile']

    第10~36行:文件上传前触发的功能。

    第11~21行:图片文件类型的过滤功能,Jquery setData函数用来设置POST至服务器端的值。

    第25~26行:设置同时只上传一个文件还是多个文件,如果只上传一个文件,则将触发按钮禁掉。如果要多传输几个文件,请在服务器端PHP文件上传程序中设置MAXSIZE的值,当然上传文件的大小限制同时和PHP.INI文件中的设置也有关。

    第28~35行:在文件上传过程中每隔200毫秒动态更新一次按钮的文字,已实现动态提示的效果。window.setInterval函数用来每隔指定的时间就执行一次内置的函数,交互时间单位为豪秒。

    第37~49行:文件上传功能完成后触发的功能,根据返回值如果服务器端报错,则前端通过ALERT方式提示出错信息。

    服务器端PHP文件上传代码

      大体上是根据之前介绍的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

    $upload_dir = '../file/';
    $file_path = $upload_dir . $_FILES['userfile']['name'];
    $MAX_SIZE = 20000000;

    echo $_POST['buttoninfo'];
    if(!is_dir($upload_dir))
    {
        if(!mkdir($upload_dir))
            echo "文件上传目录不存在并且无法创建文件上传目录";
        if(!chmod($upload_dir,0755))
            echo "文件上传目录的权限无法设定为可读可写";
    }
    if($_FILES['userfile']['size']>$MAX_SIZE)
        echo "上传的文件大小超过了规定大小";

    if($_FILES['userfile']['size'] == 0)
        echo "请选择上传的文件";

    if(!move_uploaded_file( $_FILES['userfile']['tmp_name'], $file_path))
        echo "复制文件失败,请重新上传";

    switch($_FILES['userfile']['error'])
    {
        case 0:
            echo "success" ;
            break;
        case 1:
            echo "上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值";
            break;
        case 2:
            echo "上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值";
            break;
        case 3:
            echo "文件只有部分被上传";
            break;
        case 4:
            echo "没有文件被上传";
            break;
    }


    总结

      基本上前端Ajax文件上传触发功能和服务器端PHP文件上传功能的原型就介绍完毕了,你可以根据自身需要对前后端代码进行补充,也可以将一些 功能独立出来,比如文件类型、单个文件或者多文件上传功能。总的来说Jquery插件AjaxUpload实现文件上传功能的应用还是比较容易的。

    PHP网站开发教程-leapsoul.cn版权所有,转载时请以链接形式注明原始出处及本声明,谢谢。

    原始连接(http://www.leapsoul.cn/?p=304)

  • 相关阅读:
    装饰器及其应用
    信息系统项目管理师高频考点(第九章)
    信息系统项目管理师高频考点(第八章)
    信息系统项目管理师高频考点(第七章)
    系统集成项目管理工程师高频考点(第九章)
    系统集成项目管理工程师高频考点(第八章)
    信息系统项目管理师高频考点(第六章)
    信息系统项目管理师高频考点(第五章)
    信息系统项目管理师高频考点(第四章)
    信息系统项目管理师高频考点(第三章)
  • 原文地址:https://www.cnblogs.com/xcp19870712/p/2407490.html
Copyright © 2020-2023  润新知