PHP 文件上传后端处理实用技巧方法


Posted in PHP onJanuary 06, 2017

PHP 文件上传后端处理实用技巧方法

引语:在上一篇文章中说到,在页面中可以用隐藏的方式让你的上传页面看起来漂亮。但是这对于性能来说,并没有什么卵用,那么在后台的处理中,难道就没有一些处理技巧么?所谓后台的技巧,应该要包括上传得快一点,上传的文件大一点!那么,本文就来说说,后端处理都有些什么技巧吧!

业务场景一、我们只会选择一个单个的文件上传,而且不需要做一些即时的验证工作。那么,也许并没有什么优化可言了,因为,最后你要做的,只是将这个文件放在表单里最后一起提交,直接处理即可!

业务场景二、需要上传多个文件,而且需要时时验证文件内部内容,并时行相应页面显示。对于这种况,在用户选择了上传文件之后,我们需要立即将文件上传,因为我们需要读取文件里的信息,在最后提交的时候,我们也需要提交一次文件。很明显,在这里是存在一个重复上传的工作的,一个耗费用户时间,二个是耗费服务器带宽资源!优化,能够想得到的方法也很简单,能不能在第一次上传完文件之后,就将文件保留在服务器,真正提交表单的时候,去读取这个已经被上传的临时文件即可。是的,这就是我们的处理思路!

业务场景三、与场景二类似,需要上传多个文件,但是多个文件可能是分开上传的。即我们可能第一次上传了10M,第二次上传了10M,总共上传了10次,那么,在服务器端来说的话,一次性提交肯定是超出了上传大小的限制了,但是如果,我们是分每一次的上传,这是可以的,而最后提交的时候,我们只需要将简短的文本信息传上去即可!

思路的确是简单的,看起来,也是没什么问题,但是,也许我是能力有限,当时着实花了我不少时间去处理这个什么鬼!下面,我将给出一些示例代码,以供参考:

文件上传技巧(将单次上传的文件作为临时文件存在在服务器端)示例代码:

1. 页面js处理

//点击选择完成文件后,触发上传文件操作,将文件上传至服务器临时目录
  $('.upload-real-file').off().on('change', function(){
   if(!$(this).val()){
    return false;
   }
   var responseObjId = $(this).attr('response-id');
   var responseObj = $('#' + responseObjId);
   $('#Form').ajaxSubmit({
    url:'/aa/bb/uploadTmpApkTool',
    resetForm: false,
    dataType: 'json',
    beforeSubmit: function(option){
     window.loading = layer.load(2);
    },
    success: function(data, statusText){
     layer.close(window.loading);
     if(data.status == 1){
      responseObj.html(data.apkInfoHtml);
      var parentContainer = responseObj.parent().parent(),
       nameContainer = parentContainer.find('.file-name-container');
      nameContainer.html(data.apkName);
      nameContainer.attr('title', data.apkName);
      responseObj.find('.file-tmp').html(data.fileInfo); //将文件信息存放于隐藏域中,以便在提交时能找到 
      $(submitId).removeAttr('disabled');
     }else{
      layer.alert(data.info);
     }
    },
    error: function(data){
     layer.close(window.loading);
     layer.alert('未知错误,请稍后再试!');
    }
   });
   return false;//防止dialog 自动关闭
  });

2. 很明显,页面里面需要获取文件信息,后台处理代码(PHP)

$apkConfig = $this->_getApkConfig();
  $params = $this->getFilteredParam('get');
  $subFile = $_FILES['apkToolFiles'];
  $apkName = $apkInfoHtml = "";
  if(empty($subFile))
  {
   $this->ajaxReturn(array('status' => -4, 'info' => '请选择要上传的文件'));
  }

  foreach ($subFile['name'] as $subKey => $subVal)
  {
   if ($subFile['name'][$subKey])
   {
    $fileData = $this->_getFileData($subFile, $subKey);
    $checkData = array(
     'maxSize' => $apkConfig['FILE_MAX_SIZE'],
     'savePath' => $apkConfig['TMP_CHILD_PATH'],
     'extArr' => array('apk'),
     'releaseName' => str_replace('.apk', '', $fileData['fileName']), //特有
    );
    $checkResult = $this->_checkFileData($fileData, $checkData);
    if ($checkResult['status'] != 1)
    {
     $this->ajaxReturn($checkResult);
    }
    //移动文件
    $filePath = $checkData['savePath'] . '/' . $fileData['fileName'] . '.tmp' . genRandStr(6);;
    $this->_moveUploadedFile($fileData['tmpName'], $filePath);
    $apkInfo = $this->_apkParser($filePath); //解析
    if($apkInfo['UMENG_CHANNEL'] != 'UMENG_CHANNEL_VALUE')
    {
     @unlink($filePath);        //删除无效文件
     $this->ajaxReturn(array('status' => 0, 'info' => "UMENG_CHANNEL的值要是 UMENG_CHANNEL_VALUE才行"));
    }
    $tmpFileArr['file_info'] = array(
     'name' => $subFile['name'][$subKey],
     'type' => $subFile['type'][$subKey],
     'tmp_name' => str_replace($apkConfig['TMP_CHILD_PATH'] . '/', '', $filePath),
     'error' => $subFile['error'][$subKey],
     'size' => $subFile['size'][$subKey],
    );    //转存该值,不再重复上传文件
   }
   else
   {
    $this->ajaxReturn(array('status' => 0, 'info' => "文件不能为空"));
   }
   foreach ($apkInfo as $key => $val)
   {
    $apkInfoHtml .= "{$key}:{$val} \r\n";
   }
   $apkName = $fileData['fileName'];
   $version = $apkInfo['versionName'];
  }
  $fileInfo = htmlspecialchars(json_encode($tmpFileArr['file_info']));
  $fileInfoHtml = "<input name=\"apkToolFileTmp[]\" value='{$fileInfo}' type=\"hidden\"/>"; //一定要输出前使用htmlspecialchars, 否则不能正确显示页面值和获取至正确的文件信息

  $this->ajaxReturn(array('status' => 1, 'info' => "上传成功", 'version' => $version, 'item' => $item, 'apkName' => $apkName, 'apkInfoHtml' => $apkInfoHtml, 'fileInfo' => $fileInfoHtml));
 }

3. 通过以两部分代码的配合,我们在页面上已经有正确的信息了,只需要在最后提交表单的时候, 不要将文件提交到服务器,在服务器端处理时,只需将之前上传的临时文件移动一下位置即可 ,这样就算大功告成了!

$('.upload-file-real').attr('disabled', 'disabled');  //提交表单前,禁用上传文件

4. 后续工作

将临时文件上传到服务器后,是没办法判断用户是否取消当前操作的,如果取消了,则临时文件将一直存在于服务器,所以,我们需要一个定时清理临时目录的脚本。当然,这个很简单,就只需要找到这个目录,比较一下时间,比如超过一天前的文件就给删除。注意控制清理频率即可!

5. 题外话

日志真的很重要,哪里出错了,哪里删除文件了,哪里清理数据库了,一定要做好记录,否则,到时查找原因时,到哪里去喊救命!

上传文件到服务器临时目录,后端处理原理看起来很简单,但是也需要你仔细调试,至少当初我在做这个小功能时,着实费了不少劲才缕清楚的!

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

PHP 相关文章推荐
php中计算程序运行时间的类代码
Nov 03 PHP
关于php正则匹配汉字的方法介绍
Apr 25 PHP
PHP程序漏洞产生的原因分析与防范方法说明
Mar 06 PHP
根据ip调用新浪api获取城市名并转成拼音
Mar 07 PHP
PHP针对常规模板引擎中与CSS/JSON冲突的解决方法
Aug 19 PHP
递归实现php数组转xml的代码分享
May 14 PHP
PHP使用ODBC连接数据库的方法
Jul 18 PHP
详解Yii实现分页的两种方法
Jan 14 PHP
IOS 开发之NSDictionary转换成JSON字符串
Aug 14 PHP
PHP获取MySQL执行sql语句的查询时间方法
Aug 21 PHP
php正确输出json数据的实例讲解
Aug 21 PHP
PHP 文件写入和读取操作实例详解【必看篇】
Nov 04 PHP
PHP+mysql实现从数据库获取下拉树功能示例
Jan 06 #PHP
php中简单的对称加密算法实现
Jan 05 #PHP
WAF的正确bypass
Jan 05 #PHP
phpcms的分类名称和类别名称的调用
Jan 05 #PHP
php 5.4 全新的代码复用Trait详解
Jan 05 #PHP
golang 调用 php7详解及实例
Jan 04 #PHP
PHP 与 UTF-8 的最佳实践详细介绍
Jan 04 #PHP
You might like
PHP中通过HTTP_USER_AGENT判断是否为手机移动终端的函数代码
2013/02/14 PHP
如何用php生成扭曲及旋转的验证码图片
2013/06/07 PHP
symfony表单与页面实现技巧
2015/01/26 PHP
运用jquery实现table单双行不同显示并能单行选中
2009/07/25 Javascript
js setTimeout 参数传递使用介绍
2013/08/13 Javascript
判断JS对象是否拥有某种属性的两种方式
2013/12/02 Javascript
jquery获得option的值和对option进行操作
2013/12/13 Javascript
jQuery实现的一个自定义Placeholder属性插件
2014/08/11 Javascript
javascript复制粘贴与clipboardData的使用
2014/10/16 Javascript
jQuery+Pdo编写login登陆界面
2016/08/01 Javascript
浅谈Cookie的生命周期问题
2016/08/02 Javascript
手机图片预览插件photoswipe.js使用总结
2016/08/25 Javascript
JS动态给对象添加属性和值的实现方法
2016/10/21 Javascript
javascript删除html标签函数cIsHTML
2017/01/09 Javascript
详解JavaScript RegExp对象
2017/02/04 Javascript
Vue.js 60分钟快速入门教程
2017/03/28 Javascript
通过fastclick源码分析彻底解决tap“点透”
2017/12/24 Javascript
Vue监听页面刷新和关闭功能
2019/06/20 Javascript
vue中watch和computed的区别与使用方法
2020/08/23 Javascript
前端 javascript 实现文件下载的示例
2020/11/24 Javascript
[10:42]Team Liquid Vs Newbee
2018/06/07 DOTA
Python实现测试磁盘性能的方法
2015/03/12 Python
详解Python之unittest单元测试代码
2018/01/24 Python
详解Python下Flask-ApScheduler快速指南
2018/11/04 Python
如何用css3实现switch组件开关的方法
2018/02/09 HTML / CSS
amazeui模态框弹出后立马消失并刷新页面
2020/08/19 HTML / CSS
后勤自我鉴定
2013/10/13 职场文书
《草虫的村落》教学反思
2014/02/16 职场文书
幼儿园庆六一活动方案
2014/03/06 职场文书
大专生找工作自荐书
2014/06/10 职场文书
禁止高声喧哗的标语
2014/06/11 职场文书
2014年化工厂工作总结
2014/11/25 职场文书
奖金申请报告模板
2015/05/15 职场文书
python编程简单几行代码实现视频转换Gif示例
2021/10/05 Python
一级电子管军用接收机测评
2022/04/05 无线电
VUE使用draggable实现组件拖拽
2022/04/06 Vue.js