zoukankan      html  css  js  c++  java
  • 关于php上传文件过大的表单回填

    也许标题有点绕口,有点无法让人理解。请原谅博主,语文学的不好,都赖体育老师。 问题场景重现:在某次迭代中,接到这样一个需求:当新建或编辑一个Bug(包含附件以及其他字段)上传附件过大时,退回到编辑页面,并保证数据回显。 看上去是一个很简单的问题,当附件过大时,页面重新跳转到编辑页面并回传之前Post过去的数据。可是问题来了。php.ini配置文件中upload_max_filesize的设置会限定服务器所能接受上传文件的大小。当上传的文件超过upload_max_filesize时,会拒绝改post请求,并且清空整个post数据。说明白点,除开附件数据,连同其他表单数据也一同清除了,这就导致了没有办法进行表单数据回显。 首先想到的办法是看配置文件中是否可以设置相关属性。可惜未遂,好像并不能解决上传文件过大又保留post数据的方法。然后,只能从其他方面下手。在和别人的讨论中,我逐渐尝试了3个方法。 提交前先进行保存草稿。我们的项目中,有草稿这个设置。但是,很快就被产品人员给否决了。理由简单表述如下:如果一个用户新建一个Bug,提交前保存一份草稿。当他提交失败后决定放弃此次新建,那么数据库中就会多一个没有指向现有Bug的草稿,造成脏数据和空间的浪费。我觉得有道理,否决之。 对附件单独处理进行异步提交。这也是很显而易见的想法。既然附件对提交有影响,那就对其单独处理,异步提交。可是,在以下这个场景中就显得不合适了。当一个用户新建一个Bug时,你异步提交附件,可是此时还未生成此Bug,你异步提交到哪去呢?去绑定哪一个Bug呢?显然在此场景下,又导致了这个方法的失败,不过看来已经比之前前进蛮多了。 在表单提交之前先进行一次Ajax提交用以保存其他数据。简而言之,表单的提交分为两步。第一步:Ajax提交表单数据,不写入数据库,只是单纯的保存表单数据到缓存中并生成一个cache_key用以保存。第二步:带上第一步的cache_key进行表单提交,如果失败,利用cache_key进行表单回填,如果成功,最好如此。 这里就要提到Ajax技术了。AJAX即“Asynchronous JavaScript and XML”(异步的JavaScriptXML技术),指的是一套综合了多项技术的浏览器网页开发技术。即可以在不刷新整个页面的前提下,对部分HTML节点进行更新。好像自从google百度地图运用后,良好的交互方式就使其慢慢火起来了。。。好,扯远了,回来。 我们可以利用Jquery,很方便的实现一个Ajax提交。 jQuery.ajax( options ) : 通过 HTTP 请求加载远程数据。 这个是jQuery 的底层 AJAX 实现。简单易用的高层实现见 $.get, $.post 等。 $.ajax() 返回其创建的 XMLHttpRequest 对象。大多数情况下你无需直接操作该对象,但特殊情况下可用于手动终止请求。 注意: 如果你指定了 dataType 选项,请确保服务器返回正确的 MIME 信息,(如 xml 返回 "text/xml")。错误的 MIME 类型可能导致不可预知的错误。见 Specifying the Data Type for AJAX Requests 。 当设置 datatype 类型为 'script' 的时候,所有的远程(不在同一个域中)POST请求都回转换为GET方式。 $.ajax() 只有一个参数:参数 key/value 对象,通常记为operations,包含各配置及回调函数信息。详细参数选项,可进官网查看。 这是页面上的一段代码,用来绑定Ajax提交事件。
    $('#id-tapd-toolbar').find('.for_submit').each(function() {
    			var ele_submit = document.getElementById('save' + this.id);
    			$(this).click(function() { 
    				var attachment_p = $('.attach_field_1');
    				if(attachment_p.length != 0){
    					var new_form_action = $('#bug_form').attr('action').replace(/submit/, 'ajax_submit');
    					var editor = TFL.editor.getInstance("BugDescription");
    					var description = editor.html();
    					$('#BugDescription').text(description);
    					 jQuery.ajax({
    	                    url: new_form_action,   // 提交的页面
    	                    data: $('#bug_form').serialize(), // 从表单中获取数据
    	                    type: "POST",                   // 设置请求类型为"POST",默认为"GET"
    	                    beforeSend: function()          // 设置表单提交前方法
    	                    {
    	                        // 按钮灰化
    	                    },
    	                    error: function(request) {      // 设置表单提交出错
    	                        alert(<?php t("failed to submit the form ,please try it later.") ?>);
    	                    },
    	                    success: function(msg) {
    	                    	var cacheKey = msg;
    	                    	var old_url = $('#bug_form').attr('action');
    	                    	var new_url = old_url + "&cache_key=" + cacheKey;  
    	                    	$('#bug_form').attr('action', new_url);          //更新表单的action,带上cache用于回显
    	                    	ele_submit.click();
    
                        	}
                   		});
    				} else{
    					ele_submit.click();
    				}
    
    			});
    		});
    可能注释会影响到代码的阅读。我就按照代码的顺序,简单的说一下思路。 首先,变量ele_submit得到提交按钮的ID,如果当前包含附件提交的话,那么将表单提交的url改为ajax_submit。变量description是对富文本框的特殊处理。jQuery.ajax()是接下来的重点。可见ajax方法的参数就是一些key/value值,简单明了。url指明提交的页面;data指明提交时包含的数据;type表明请求类型;beforeSend是提交前的方法,例如对页面元素和数据的处理等;error指明提交失败后执行的内容,譬如弹窗报错等;success指明提交成功后的执行内容,参数即为响应数据。 重点看一下success里面的方法。显然ajax_submit请求会返回一段缓存key值cache_key,并加在表单的旧url上,最后进行表单提交。应该是清晰明了的代码吧。 下面贴下服务器端的代码:
    function ajax_submit(){
         $ajax_result = array();
         $this->layout = "ajax";
        $cache_key = 'SUBMIT_BUG_WITH_ATTACHMENT_' . time();
        MyCache::add($cache_key, $this->data, '+5 mins');		
    		echo $cache_key;
    		exit;
    	}
    很简单,用post过来的数据生成一个缓存,并将缓存key响应回去给ajax的success方法。 接下来,是当失败后回填数据的代码,也很简单,只要保证数据字段对应就行了。
    		if(isset($this->params['url']['cache_key'])){     //第一次提交后会有cache_key,用以保存表单数据
    			$temp_key = $this->params['url']['cache_key'];
    			$old_data = MyCache::get($temp_key);
    			$this->set("old_data", $old_data);
    			if(isset($old_data['BugStoryRelation']['BugStoryRelation_relative_id'])){
    				$fields['BugStoryRelation_relative_id']['default']=$old_data['BugStoryRelation']['BugStoryRelation_relative_id'];
    			}
    			foreach ($old_data['Bug'] as $key => $value) {   //用cache里面的数据更新fields,保证当数据过大时数据能正确回显  by jeremy
    				if(!empty($value) && array_key_exists($key, $fields)){
    					if(is_array($value)){
    						$fields[$key]['default'] = $value[0];
    					} else{
    						$fields[$key]['default'] = $value;
    					}
    
    				}
    			}
    		}
    还有一些特殊需要处理的地方,不是本文的重点,就不列举了。 总之,这是一次很好的Ajax实践,jQuery封装的很好,在实现的过程中,暴露了自己对前端技术知识的漏洞,以后要找机会慢慢加强这方面的锻炼。 另外,三天后就离开腾讯结束自己的实习生活了,心有不舍,自己也在腾讯的代码库中留下了自己的印迹,不知道能保存多久呢。。。此时正在为导出Excel的一个问题伤神。在测试环境上好用,在正式环境下出问题,Bug都不好定为,真是蛋疼。。。。
  • 相关阅读:
    用confluence完成室项目管理网站的初步搭建
    初中英语单词词库 for supermemo
    用supermemo背单词4年了
    武汉一点印象
    借个iPad玩玩,越狱4.2.1成功
    TIOBE在2011年3月发布的编程语言排名表
    复杂的工作机构,一把手真是不易
    自己做的项目竟然与马拉松石油公司的数字油田思路惊人的相似!
    iPhone开发笔记[1/50]:初学iPhone上用Quartz 2D画图
    背单词的词条终于达到6500
  • 原文地址:https://www.cnblogs.com/No-body/p/4207293.html
Copyright © 2011-2022 走看看