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 4.2书写安全的脚本
Oct 09 PHP
PHP中的float类型使用说明
Jul 27 PHP
在yii中新增一个用户验证的方法详解
Jun 20 PHP
PHP实现将textarea的值根据回车换行拆分至数组
Jun 10 PHP
PHP使用缓存即时输出内容(output buffering)的方法
Aug 03 PHP
PHP面向对象编程之深入理解方法重载与方法覆盖(多态)
Dec 24 PHP
深入理解php printf() 输出格式化的字符串
May 23 PHP
centos 7.2下搭建LNMP环境教程
Nov 20 PHP
常用PHP封装分页工具类
Jan 14 PHP
基于 Swoole 的微信扫码登录功能实现代码
Jan 15 PHP
Laravel关系模型指定条件查询方法
Oct 10 PHP
PHP框架实现WebSocket在线聊天通讯系统
Nov 21 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中PDO解决中文乱码问题的一些补充
2010/09/06 PHP
php批量缩放图片的代码[ini参数控制]
2011/02/11 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
2017/11/10 PHP
Laravel路由研究之domain解决多域名问题的方法示例
2019/04/04 PHP
基于ThinkPHP5框架使用QueryList爬取并存入mysql数据库操作示例
2019/05/25 PHP
理解 JavaScript 预解析
2009/10/25 Javascript
获取body标签的两种方法
2011/10/13 Javascript
《JavaScript高级程序设计》阅读笔记(三) ECMAScript中的引用类型
2012/02/27 Javascript
select、radio表单回显功能实现避免使用jquery载入赋值
2013/06/08 Javascript
谷歌浏览器调试JavaScript小技巧
2014/12/29 Javascript
javascript中setInterval的用法
2015/07/19 Javascript
JavaScript实现添加及删除事件的方法小结
2015/08/04 Javascript
JS 动态判断PC和手机浏览器实现代码
2016/09/21 Javascript
JS定时器实现数值从0到10来回变化
2016/12/09 Javascript
angularjs过滤器--filter与ng-repeat配合有奇效
2017/04/20 Javascript
微信小程序实现基于三元运算验证手机号/姓名功能示例
2019/01/19 Javascript
解决layui富文本编辑器图片上传无法回显的问题
2019/09/18 Javascript
JavaScript常用工具函数库汇总
2020/09/17 Javascript
微信小程序实现锚点跳转
2020/11/23 Javascript
[01:06:42]VP vs NewBee Supermajor 胜者组 BO3 第二场 6.5
2018/06/06 DOTA
在Python中使用dict和set方法的教程
2015/04/27 Python
Python中%是什么意思?python中百分号如何使用?
2018/03/20 Python
numpy下的flatten()函数用法详解
2019/05/27 Python
用Python+OpenCV对比图像质量的几种方法
2019/07/15 Python
基于Python 中函数的 收集参数 机制
2019/12/21 Python
Django后台管理系统的图文使用教学
2020/01/20 Python
django修改models重建数据库的操作
2020/03/31 Python
使用python+poco+夜神模拟器进行自动化测试实例
2020/04/23 Python
Booking.com西班牙:全球酒店预订
2018/03/30 全球购物
酒店总经理助理岗位职责
2014/02/01 职场文书
中式婚礼主持词
2014/03/13 职场文书
纠纷协议书
2014/04/16 职场文书
作风建设演讲稿
2014/05/23 职场文书
优秀员工自荐书
2015/03/06 职场文书
物业保洁员管理制度
2015/08/05 职场文书
正确使用MySQL update语句
2021/05/26 MySQL