关于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 参数,这个参数是由应用程序自行产生,它会用来识别每 ...
随机推荐
- weblogic 反序列化补丁绕过漏洞的一个批量检测shell脚本(CVE-2017-3248 )
~ 以下内容,仅供学习参考 ~ weblogic 反序列化补丁绕过漏洞已经出了两个月了,balabala ~~~ 废话不说,拿到该漏洞的利用工具weblogic.jar,但只能一个个检测ip和端口,效 ...
- JavaScript辅助响应式
js响应式 rem辅助响应式布局:其实就是指在HTML页面的大小不断变化的时候,里面的宽.高.字体等等也随之变化,主要是通过获取window.innerwidth的值来进行判断,7.5rem===10 ...
- oracle05
1. 数据处理 说完了所有的查询,下面说说增.删.改. 1.1. Update 在plsql Developer工具中,加上rowid可以更改数据. 使用工具进行更新数据的操作 在工具中更新数据方式一 ...
- [转]softmax函数详解
答案来自专栏:机器学习算法与自然语言处理 详解softmax函数以及相关求导过程 这几天学习了一下softmax激活函数,以及它的梯度求导过程,整理一下便于分享和交流. softmax函数 softm ...
- nginx 实现mysql的负载均衡【转】
默认Nginx只支持http的反向代理,要想nginx支持tcp的反向代理,还需要在编译时增加tcp代理模块支持,即nginx_tcp_proxy_module 下面操作步骤只让nginx支持tcp_ ...
- win7 64位mysql安装及navicat 解压版
教程:http://jingyan.baidu.com/article/f3ad7d0ffc061a09c3345bf0.html Mysql修改设置root密码的命令及方法:http://jingy ...
- unity 2d 游戏优化之路 遇坑记录
情景说明: unity 出的Android包,在目前一些主流机型跑都没有问题,但是在 小米3 这种比较老的机器上跑,报如下错误 GLSL compilation failed, no infolog ...
- Filter过滤器-JavaWeb三大组件之一
Servlet.Filter.Listener是JavaWeb的三大组件,给Web开发提供了很大的便利. 什么是Filter? Filter,过滤器.类似与生活中的净水器.空气净化器. JavaWeb ...
- github后端开发面试题大集合(三)
作者:小海胆链接:https://www.nowcoder.com/discuss/3616来源:牛客网 13.软件架构相关问题: 什么情况下缓存是没用的,甚至是危险的? 为什么事件驱动的架构能提高可 ...
- Kubernetes监控:部署Heapster、InfluxDB和Grafana
本节内容: Kubernetes 监控方案 Heapster.InfluxDB和Grafana介绍 安装配置Heapster.InfluxDB和Grafana 访问 grafana 访问 influx ...