• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

关于php上传文件过大的表单回填

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
也许标题有点绕口,有点无法让人理解。请原谅博主,语文学的不好,都赖体育老师。 问题场景重现:在某次迭代中,接到这样一个需求:当新建或编辑一个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都不好定为,真是蛋疼。。。。

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
phpwindows环境安装Apache-apollo+phpMQTT实现发送MQTT发布时间:2022-07-10
下一篇:
php文件头部(header)发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap