关于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”(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。即可以在不刷新整个页面的前提下,对部分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都不好定为,真是蛋疼。。。。
关于php上传文件过大的表单回填的更多相关文章
- JSP SMARTUPLOAD组件:上传文件时同时获取表单参数
原因很简单: 注意更改from 属性啊!否则为null! 因为你用jspsmartuploadsmart时post请求 的格式是multipart/form-data,即enctype="m ...
- ajax上传文件 基于jquery form表单上传文件
<script src="/static/js/jquery.js"></script><script> $("#reg-btn&qu ...
- [转]javascript实现限制上传文件的大小
本文转自:http://www.micmiu.com/lang/javascript/js-check-filesize/ 目录 基本思路 示例 [一].基本思路 在FireFox.Chrome浏览器 ...
- 使用WebClient上传文件并同时Post表单数据字段到服务端
之前遇到一个问题,就是使用WebClient上传文件的同时,还要Post表单数据字段,一开始以为WebClient可以直接做到,结果发现如果先 Post表单字段,就只能获取到字段及其值,如果先上传文件 ...
- HTML上传文件支持大文件上传,下载
上传 1.修改配置文件web.config,在<system.webServer>下面加入 <security> <requestFiltering > <r ...
- .net上传文件,大文件及下载方式汇总(转)
原文地址:http://www.360doc.com/content/19/1219/10/67993814_880731215.shtml Brettle.Web.NeatUpload.dll 文件 ...
- Form key length limit 2048 exceeded ,提交数据时,数据的键过长 或者是上传文件过大
在ASP.NET Core MVC中,文件的key 默认最大为2048,文件上传的最大上传文件默认为20MB,如果我们想上传一些比较大的文件,就不知道怎么去设置了,没有了Web.Config我们应该如 ...
- js上传文件过大导致上传失败原因以及解决办法
背景:项目需要用到上传视频功能,由于视频有知识产权,要求必须上传到自己的服务器上不允许用第三方视频网站接口上传,于是一开始开始用的是input type=file去上传,小的视频上传没有问题,上传将近 ...
- c# 模拟表单提交,post form 上传文件、大数据内容
表单提交协议规定:要先将 HTTP 要求的 Content-Type 设为 multipart/form-data,而且要设定一个 boundary 参数,这个参数是由应用程序自行产生,它会用来识别每 ...
随机推荐
- 【Linux 命令】sed 命令
文章转载自:https://www.jianshu.com/p/779f40985b20 文本分隔:------ # 在每一行后面增加一空行. sed G # 在每一行后面增加两行空行. sed &q ...
- 2017ACM暑期多校联合训练 - Team 9 1010 HDU 6170 Two strings (dp)
题目链接 Problem Description Giving two strings and you should judge if they are matched. The first stri ...
- scrapy 爬虫踩过的坑(II)
同事写了个爬虫,逻辑上看着没什么问题,但是一直报错:Request url must be str or unicode…… 打印了一下url 和url 的类型,确实是 unicode 懵逼…… 打印 ...
- 【navicat112_premium】navicat112_premium数据库连接工具安装过程
此工具及其方便,可以连接mysql.oracle.sqlserver登数据库... 1.下载安装包Navicat Premium_11.2.7简体中文版.rar 下载地址:http://qiaoliq ...
- 88.modelsim仿真do文件相关技巧
网上的关于DO文件的编写好像资料不多,比较杂,所以本人总结一下常用的简单语法,方便大家查看.其实本人也刚接触DO文件没多久,有纰漏很正常,欢迎指正批评,互相学习.PS:写得有点乱 还有一个值得注意 ...
- docker 错误排查:无法进入容器.
docker 错误排查:无法进入容器. #docker exec -it 3c1d bash rpc error: code = 2 desc = oci runtime error: exec fa ...
- day08作业
1.A.在类中的位置不同 成员变量:在类中方法外 局部变量:在方法定义中或者方法声明上 B.在内存中的位置不同 成员变量:在堆内存(成员变量属于对象,对象进堆内存) 局部变量:在栈内存(局部变量属于方 ...
- Jquery获取radio单选按钮的value与后面的文字
一组单选按钮如图: <input name="classId" value="8afa94f45ba3e2c1015ba3fac6c00000" type ...
- python图片处理(一)
在matlab中有相应的图像进行二值化处理,并且标记连通区域 L = bwlabel(BW,n) 返回一个和BW大小相同的L矩阵,包含了标记连BW中每个连通区域的类别标签,标签的值是1.2.num(连 ...
- Java事务管理之JDBC
前言 关于Java中JDBC的一些使用可以参见: Java 中使用JDBC连接数据库例程与注意事项 在使用JDBC的使用, 如何进行事务的管理.直接看一下代码 示例代码 /** * @Title: J ...