php文件上传后端处理小技巧


Posted in PHP onMay 22, 2016

本文就来说说,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 相关文章推荐
发布一个用PHP fsockopen写的HTTP下载的类
Feb 22 PHP
PHP垃圾回收机制简单说明
Jul 22 PHP
php expects parameter 1 to be resource, array given 错误
Mar 23 PHP
PHP中extract()函数的定义和用法
Aug 17 PHP
php处理文件的小例子(解压缩,删除目录)
Feb 03 PHP
php获取目标函数执行时间示例
Mar 04 PHP
使用GD库生成带阴影文字的图片
Mar 27 PHP
在WordPress中获取数据库字段内容和添加主题设置菜单
Jan 11 PHP
php通过文件头判断格式的方法
May 28 PHP
php实现微信企业号支付个人的方法详解
Jul 26 PHP
PHP实现唤起微信支付功能
Feb 18 PHP
PHP中abstract(抽象)、final(最终)和static(静态)原理与用法详解
Jun 05 PHP
PHP strip_tags() 去字符串中的 HTML、XML 以及 PHP 标签的函数
May 22 #PHP
PHP+MySql+jQuery实现的&quot;顶&quot;和&quot;踩&quot;投票功能
May 21 #PHP
制作个性化的WordPress登陆界面的实例教程
May 21 #PHP
详解WordPress中添加友情链接的方法
May 21 #PHP
PHP框架Laravel插件Pagination实现自定义分页
Apr 22 #PHP
屏蔽PHP默认设置中的Notice警告的方法
May 20 #PHP
PHP获取网站中各文章的第一张图片的代码示例
May 20 #PHP
You might like
探讨:如何通过stats命令分析Memcached的内部状态
2013/06/14 PHP
php实现生成带二维码图片并强制下载功能
2018/02/24 PHP
Laravel自动生成UUID,从建表到使用详解
2019/10/24 PHP
JSON 入门指南 想了解json的朋友可以看下
2009/08/26 Javascript
javascript中String类的subString()方法和slice()方法
2011/05/24 Javascript
Javascript面向对象编程(三) 非构造函数的继承
2011/08/28 Javascript
ASP.NET jQuery 实例16 通过控件CustomValidator验证RadioButtonList
2012/02/03 Javascript
解决javascript:window.close()在chrome,Firefox下失效的问题
2013/05/07 Javascript
ZeroClipboard插件实现多浏览器复制功能(支持firefox、chrome、ie6)
2014/08/30 Javascript
jQuery的事件委托实例分析
2015/07/15 Javascript
jQuery支持添加事件的日历特效代码分享(3种样式)
2015/08/24 Javascript
javascript拖拽效果延伸学习
2016/04/04 Javascript
BootstrapValidator不触发校验的实现代码
2016/09/28 Javascript
JS中传递参数的几种不同方法比较
2017/01/20 Javascript
浅谈webpack-dev-server的配置和使用
2018/05/17 Javascript
vue elementUI table 自定义表头和行合并的实例代码
2019/05/22 Javascript
[05:02]2014DOTA2 TI中国区预选赛精彩TOPPLAY第三弹
2014/06/25 DOTA
Python实现扫描局域网活动ip(扫描在线电脑)
2015/04/28 Python
详解在Python的Django框架中创建模板库的方法
2015/07/20 Python
各个系统下的Python解释器相关安装方法
2015/10/12 Python
docker django无法访问redis容器的解决方法
2019/08/21 Python
Python MongoDB 插入数据时已存在则不执行,不存在则插入的解决方法
2019/09/24 Python
CSS3线性渐变简单实现以及该属性在浏览器中的不同
2012/12/12 HTML / CSS
css3 盒模型以及box-sizing属性全面了解
2016/09/20 HTML / CSS
详解Html5原生拖拽操作
2018/01/12 HTML / CSS
澳洲在线厨具商店:Kitchen Style
2018/05/05 全球购物
日本最佳原创设计品牌:Felissimo(芬理希梦)
2019/03/19 全球购物
Zavvi西班牙:电子游戏、极客服装、Blu-ray、Funko Pop等
2019/05/03 全球购物
环境工程求职简历的自我评价范文
2013/10/24 职场文书
家长会演讲稿
2014/04/26 职场文书
语文教师求职信范文
2015/03/20 职场文书
青年干部培训班学习心得体会
2016/01/06 职场文书
员工保密协议范本,您一定得收藏!很有用!
2019/08/08 职场文书
详解overflow:hidden的作用(溢出隐藏、清除浮动、解决外边距塌陷)
2021/07/01 HTML / CSS
MySQL分区表实现按月份归类
2021/11/01 MySQL
MySQL中order by的执行过程
2022/06/05 MySQL