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 相关文章推荐
Apache设置虚拟WEB
Oct 09 PHP
提高PHP编程效率 引入缓存机制提升性能
Feb 15 PHP
创建数据库php代码 用PHP写出自己的BLOG系统
Apr 12 PHP
PHP使用strtotime计算两个给定日期之间天数的方法
Mar 18 PHP
PHP超全局数组(Superglobals)介绍
Jul 01 PHP
网页的分页下标生成代码(PHP后端方法)
Feb 03 PHP
PHP中set_include_path()函数相关用法分析
Jul 18 PHP
php实现的双色球算法示例
Jun 20 PHP
浅谈使用 Yii2 AssetBundle 中 $publishOptions 的正确姿势
Nov 08 PHP
PHP convert_uudecode()函数讲解
Feb 14 PHP
ThinkPHP5.0框架使用build 自动生成模块操作示例
Apr 11 PHP
PHP Web表单生成器案例分析
Jun 02 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
php文本转图片自动换行的方法
2013/03/13 PHP
setcookie中Cannot modify header information-headers already sent by错误的解决方法详解
2013/05/08 PHP
深入剖析浏览器退出之后php还会继续执行么
2016/05/17 PHP
PHP中SERIALIZE和JSON的序列化与反序列化操作区别分析
2016/10/11 PHP
解决laravel session失效的问题
2019/10/14 PHP
Thinkphp5框架中引入Markdown编辑器操作示例
2020/06/03 PHP
再谈IE中Flash控件的自动激活 ObjectWrap
2007/03/09 Javascript
jquery 1.3.2 IE8中的一点点的小问题解决方法
2009/07/10 Javascript
jquery delay()介绍及使用指南
2014/09/02 Javascript
AngularJS的表单使用详解
2015/06/17 Javascript
Bootstrap模块dropdown实现下拉框响应
2016/05/22 Javascript
基于jquery实现弹幕效果
2016/09/29 Javascript
bootstarp modal框居中显示的实现代码
2017/02/18 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
2018/10/18 Javascript
微信小程序实现左滑修改、删除功能
2020/10/19 Javascript
node.js中process进程的概念和child_process子进程模块的使用方法示例
2020/02/11 Javascript
js实现鼠标拖曳效果
2020/12/30 Javascript
对python抓取需要登录网站数据的方法详解
2018/05/21 Python
在python中实现同行输入/接收多个数据的示例
2019/07/20 Python
Python使用random模块生成随机数操作实例详解
2019/09/17 Python
使用pyecharts1.7进行简单的可视化大全
2020/05/17 Python
Python实现定时监测网站运行状态的示例代码
2020/09/30 Python
matplotlib运行时配置(Runtime Configuration,rc)参数rcParams解析
2021/01/05 Python
详解Python中的Lock和Rlock
2021/01/26 Python
Expedia印度:您的一站式在线旅游网站
2017/08/24 全球购物
合伙经营协议书范本
2014/09/13 职场文书
微笑面对生活演讲稿
2014/09/23 职场文书
群众路线查摆问题整改措施
2014/10/10 职场文书
2015年医院工作总结范文
2015/04/09 职场文书
学校百日安全活动总结
2015/05/07 职场文书
妇产科护理心得体会
2016/01/22 职场文书
2016年教代会开幕词
2016/03/04 职场文书
2019最新版股权转让及委托持股协议书范本
2019/08/07 职场文书
Pytorch 如何加速Dataloader提升数据读取速度
2021/05/28 Python
用Python可视化新冠疫情数据
2022/01/18 Python
jdbc中自带MySQL 连接池实践示例
2022/07/23 MySQL