β

thinkphp无刷新上传+无刷新发布日志

罗迦费升格 2214 阅读

在这个特效横幅的web时代,作为phper也需要跟得上潮流。于是乎,着手研究无刷新上传+无刷新发布日志。

对于无刷新提交文字之类,jquery都已经提供了很好的功能。只需要.get / .post 就可以快速建立一个无刷新提交表单了。但是在文件上传方面,jquery明显遇到难题了(HTML5加强了上传文件功能)。网上有使用iframe这种伪ajax上传文件方式,本文就不在这里讨论了。感兴趣的,可以到开源中国查找。

本文也不讲解thinkphp的无刷新提交日志(不懂的去看官网的示例代码)。主要在无刷新上传 + 无刷新发布日志 整合上。下面的全程讲解,都围绕thinkphp框架为主,原生PHP实现方式也相差不大。

网上比较流行的无刷新上传组建有:swfupload 和uploadify 。我是用uploadify的。

模板代码 index.html:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>UploadiFive Test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="http://redich.com/03/__ROOT__/test/js/jquery.uploadify.min.js" type="text/javascript"></script>
<script type="text/javascript" src="http://redich.com/03/__ROOT__/test/js/jquery.form.js"></script>
<script>
$(function(){
    $('#from').ajaxForm({
        success:       complete,
        dataType: 'json'
    });
    function complete(data){
        if (data.status==1){
            $('#result').html(data.info).show();
            $('#error').hide();
        }else{
            $('#error').html(data.info).show();
            $('#result').hide();
        }
    }

});
</script>
<link rel="stylesheet" type="text/css" href="http://redich.com/03/__ROOT__/test/js/uploadify.css">
<style type="text/css">
body {
    font: 13px Arial, Helvetica, Sans-serif;
}
</style>
</head>

<body>
<div id="warp">
    <h1>上传文件和发表文章AJAX示例</h1>
    <div id="reload"><a href="http://redich.com/03/__URL__/reload">重新提交文章</a></div>
    <div id="result" style="display:none;"></div>
    <div id="error" style="display:none;"></div>
    <form id="from" action="__URL__/add" method="post">
        <p><label for="title">标题</label></p>
        <p><input type="text" name="title"></p>
        <p><label for="author">作者名称</label></p>
        <p><input type="text" name="author"></p>
        <p><label for="content">内容</label></p>
        <p><textarea name="content" rows="15"></textarea></p>
        <div id="queue"></div>
        <p><input id="file_upload" name="file_upload" type="file" multiple></p>
        <div id="uploadsuccess" style="display:none;"></div>
        <p><a href="javascript:$('#file_upload').uploadify('upload')">上传</a>
           <a href="javascript:$('#file_upload').uploadify('cancel','*')">重置上传队列</a>
        </p>
        <p><input type="submit" value="发表" id="submit"></p>
    </form>

    <script type="text/javascript">
var img_id_upload=new Array();//初始化数组,存储已经上传的图片名
var i=0;//初始化数组下标
        $(function() {
            $('#file_upload').uploadify({
                'swf'      : '__ROOT__/test/js/uploadify.swf',
                'uploader' : '__URL__/upload',
                'auto'     : false,//关闭自动上传
                'multi'    : false,//允许同时上传多张图
                'buttonText' : '请选择图片',//设置按钮文本片
                'queueSizeLimit' : 1,//上传队列最多显示多少个
                'onUploadSuccess' : function(file, data, response) {
                       $('#uploadsuccess').html(data).show();
                }
            });
        });
    </script>
</div>
</body>
</html>

Action部分代码 IndexAction.php

<?php
class IndexAction extends Action {
    public function index(){
    $this->display();
    }

    /*
    *
    *上传文件
    *
    */
    public function upload(){
        import("ORG.Net.UploadFile");
        $upload = new UploadFile();
        $upload->maxSize  = 10485760 ;
        $upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');
        $upload->savePath =  'test/';
        if(!$upload->upload()) {
            echo $upload->getErrorMsg();
            exit;
        }else{
            //删除旧文件
            if(session('?savename')){
                if(file_exists('test/'.session('savename'))){
                    unlink('test/'.session('savename'));
                    session('savename',NULL);//清除session记录
                }
            }
            $info =  $upload->getUploadFileInfo();
            session('savename',$info[0]['savename']);
        }
        echo '文件"'.$info[0]['name'].'"上传成功!<br />重新上传将删除刚才上传的文件。';
    }

    /*
    *
    *提交文章
    *
    */
    public function add(){
        //防止重复提交
        if(!session('?insid')){
            $test['title'] = $this->input('title','请输入标题');
            $test['author'] = $this->input('author','请输入作者名称');
            $test['content'] = $this->input('content','请输入内容');
            if(!session('?savename')){
                $this->error('请选择上传的文件!');
            }
            $test['filename'] = session('savename');
            $sql = M('test');
            $result = $sql->add($test);
            if($result !== false){
                $last_id = $sql->getLastInsID();
                session('insid',$last_id);//设置一个防重复提交的session insid
                session('savename',NULL);//释放上传文件的session
                $this->success('文章发表成功!');
            }else{
                $this->error('文章发表失败,请重新提交');            
            }
        }else{
            $this->error('请勿重复提交!');
        }
    }

    /*
    *
    *重新提交文章
    *
    */
    public function reload(){
        if(session('?savename')){//检查用户是否上传了文件。然后点击了重新提交文章。
            if(file_exists('test/'.session('savename'))){
                unlink('test/'.session('savename'));
                session('savename',NULL);
            }
        }else{
            session('savename',NULL);//释放上传文件的session
        }
        session('insid',NULL);
        redirect(__APP__);//重定向
    }

    public function input($name,$erroinfo){
        $name = $this->_POST($name,'trim,htmlspecialchars,strip_tags');
        if(empty($name)){
            $this->error($erroinfo);
            return ;    
        }
        return $name;
    }
}

说一下思路:

首先,通常用户是填写好内容后,选择好上传文件后,提交表单到服务后端,后端进行结果返回。因为用到无刷新上传,所以上传会成为第一个提交到后端处理的。
于是,我想到用session来作一个记录。虽然可以通过返回的结果放到隐藏input表单或者隐藏iframe里面,但是这样的做法很不安全。要是用户对表单的内容进行修改了,那么就会记录错误的文件了。在上述代码中,可以看到我有多次验证上传文件的session是否有设置。有则删除旧文件,再释放出来。

接着因为用到ajax提交表单内容,为了避免用户重复点击提交按钮,导致文章重复写入数据库。我使用了一个session来防止用户重复提交。尽管可以用js来讲按钮失效。但是这样的做法是极度不安全的。

最后,当用户再次点击重新提交文章后。会再次对上传文件的session检查一次。因为可能会存在这样的情况:用户提交了上传文件,但是没有点击提交按钮。这样就上传了一个没用文件到服务器了。检查完毕,再释放防止重复写入的session值。这里有一个BUG:就是要是用户直接关闭浏览器,那么文件就无法删除了= =||。这个各位就自己研究方案吧(给点提示:可以做一个判断,用户离开浏览器后,进行文件删除。因为只有上传成功后,上传文件session才是被释放的)。

文章尾部,我有一点疑问:uploadify为什么定义了错误信息后,还是会弹出英文错误的?难道只能直接改源码部分吗?如果你知道如何解决,请帖出代码指点一下我吧。谢过了

演示地址:http://redich.com/paoyapao/test/

下载地址:http://adf.ly/KYOH0

作者:罗迦费升格
技术 软件 生活
原文地址:thinkphp无刷新上传+无刷新发布日志, 感谢原作者分享。

发表评论