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获取网站域名和地址的代码
Aug 17 PHP
php 遍历显示文件夹下所有目录、所有文件的函数,没有分页的代码
Nov 14 PHP
PHP验证码类代码( 最新修改,完全定制化! )
Dec 02 PHP
深入HTTP响应状态码速查表的详解
Jun 07 PHP
PHP实现把数字ID转字母ID
Aug 12 PHP
PHP empty函数报错解决办法
Mar 06 PHP
phpStudy访问速度慢和启动失败的解决办法
Nov 19 PHP
微信支付PHP SDK之微信公众号支付代码详解
Dec 09 PHP
PHP实现简易blog的制作
Oct 24 PHP
php 基础函数
Feb 10 PHP
php中pcntl_fork创建子进程的方法实例
Mar 14 PHP
如何重写Laravel异常处理类详解
Dec 20 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动态图像的创建
2006/10/09 PHP
如何在PHP中使用Oracle数据库(1)
2006/10/09 PHP
php如何解决无法上传大于8M的文件问题
2014/03/10 PHP
js实现的仿新浪微博完美的时间组件升级版
2011/12/20 Javascript
JQuery在页面中添加和除移DOM示例代码
2013/06/24 Javascript
判定是否原生方法的JS代码
2013/11/12 Javascript
js读取csv文件并使用json显示出来
2015/01/09 Javascript
基于JavaScript实现通用tab选项卡(通用性强)
2016/01/07 Javascript
Javascript函数中的arguments.callee用法实例分析
2016/09/16 Javascript
Node.JS中事件轮询(Event Loop)的解析
2017/02/25 Javascript
webpack 4.0.0-beta.0版本新特性介绍
2018/02/10 Javascript
解决Vue打包之后文件路径出错的问题
2018/03/06 Javascript
axios 封装上传文件的请求方法
2018/09/26 Javascript
jQuery实现图片下载代码
2019/07/18 jQuery
JS中的算法与数据结构之链表(Linked-list)实例详解
2019/08/20 Javascript
p5.js实现故宫橘猫赏秋图动画
2019/10/23 Javascript
详解Python验证码识别
2016/01/25 Python
浅谈Python爬取网页的编码处理
2016/11/04 Python
Python自定义函数定义,参数,调用代码解析
2017/12/27 Python
Python实现PS滤镜中马赛克效果示例
2018/01/20 Python
Java实现的执行python脚本工具类示例【使用jython.jar】
2018/03/29 Python
python把ipynb文件转换成pdf文件过程详解
2019/07/09 Python
python中append实例用法总结
2019/07/30 Python
Python 函数绘图及函数图像微分与积分
2019/11/20 Python
Keras-多输入多输出实例(多任务)
2020/06/22 Python
python 发送邮件的示例代码(Python2/3都可以直接使用)
2020/12/03 Python
THE OUTNET美国官网:国际设计师品牌折扣网站
2017/03/07 全球购物
一份比较全的PHP面试题
2016/07/29 面试题
办公室经理岗位职责
2014/01/01 职场文书
会议邀请函
2015/01/30 职场文书
2016社区平安家庭事迹材料
2016/02/26 职场文书
2019学校运动会开幕词
2019/05/13 职场文书
2019企业给员工的慰问信
2019/06/24 职场文书
Java获取e.printStackTrace()打印的信息方式
2021/08/07 Java/Android
JavaScript最完整的深浅拷贝实现方式详解
2022/02/28 Javascript
Python如何让字典保持有序排列
2022/04/29 Python