首页 > 编程语言 >PHP如何上传超大文件

PHP如何上传超大文件

时间:2023-09-20 16:23:34浏览次数:43  
标签:info 超大 block file PHP 上传 DS dir

前言

最近在开发一个视频播放网站,用的是PHP技术。视频播放网站用户上传的都是视频资料,小的有几十M,大的都超过G了,对于这种超大文件的上传,我们不能用常规的上传方式,必须对大文件进行分块上传,否则一方面会造成服务器内存爆满,另一方如果上传的文件太大也很容造成上传超时的情况发生。

PHP上传超大文件代码

index.html

<div class="form-group">

    <label class="col-sm-2 control-label no-padding-right" for="form-field-1"> 上传视频 </label>

    <div class="col-sm-6">

        <div id="uploader" class="wu-example">

            <!--堆代码 duidaima.com -->

            <!--用来存放文件信息-->

            <div class="filename"></div>

            <div class="state"></div>

            <div class="progress">

                <div class="progress-bar progress-bar-info progress-bar-striped active" role="progressbar" aria-valuenow="40" aria-valuemin="0"

                    aria-valuemax="100" style="width: 0%">

                    <span class="sr-only">40% Complete (success)</span>

            </div>

        </div>

        <input type="hidden" name="video">

        <div class="btns">

            <div id="picker">选择文件</div>

            <button id="ctlBtn" class="btn btn-default">开始上传</button>

            <div id="pause" class="btn btn-danger">暂停上传</div>

        </div>

    </div>

</div>

</div>

<link rel="stylesheet" href="__PUBLIC__/webuploader/webuploader.css">

<script type="http://fex.baidu.com/webuploader/js/jquery-1.10.2.min.js"></script>

<script src="__PUBLIC__/webuploader/webuploader.min.js"></script>

<script>

     $(function(){

 

        var fileMd5; 

       //监听分块上传过程中的三个时间点 

       WebUploader.Uploader.register({ 

           "before-send-file":"beforeSendFile", 

           "before-send":"beforeSend", 

           "after-send-file":"afterSendFile", 

       },{ 

           //时间点1:所有分块进行上传之前调用此函数 

           beforeSendFile:function(file){ 

               var deferred = WebUploader.Deferred(); 

               //1、计算文件的唯一标记,用于断点续传 

               (new WebUploader.Uploader()).md5File(file,0,10*1024*1024) 

                   .progress(function(percentage){ 

                       // $('#item1').find("p.state").text("正在读取文件信息..."); 

                   }) 

                   .then(function(val){ 

                       fileMd5=val; 

                       // $('#item1').find("p.state").text("成功获取文件信息..."); 

                       //获取文件信息后进入下一步 

                       deferred.resolve(); 

                   }); 

               return deferred.promise(); 

           }, 

           //时间点2:如果有分块上传,则每个分块上传之前调用此函数 

           beforeSend:function(block){ 

               var deferred = WebUploader.Deferred(); 

               // 同步校验,防止没校验完就上传了

               $.ajaxSetup({async : false});

               $.ajax({ 

                   type:"POST", 

                   url:"{:url('Ajax/check_breakpoint')}", 

                   data:{ 

                       //文件唯一标记 

                       fileMd5:fileMd5, 

                       //当前分块下标 

                       chunk:block.chunk, 

                       //当前分块大小 

                       chunkSize:block.end-block.start,

                       chunks:block.chunks

                   }, 

                   dataType:"json", 

                   success:function(response){ 

                       if(response.ifExist==1){ 

                           //分块存在,跳过 

                           deferred.reject(); 

                       }else{ 

                           //分块不存在或不完整,重新发送该分块内容 

                           deferred.resolve(); 

                       } 

                   } 

               }); 

               $.ajaxSetup({async : true}); 

               this.owner.options.formData.fileMd5 = fileMd5; 

               deferred.resolve(); 

               return deferred.promise(); 

           }, 

           //时间点3:所有分块上传成功后调用此函数 

           afterSendFile:function(file){ 

               //如果分块上传成功,则通知后台合并分块 

                     $.post("{:url('Ajax/vupload_merge')}", { fileMd5: fileMd5, fileName: file.name }, function (data) {

                       if (data==0) {

                           $("#uploader .state").html("上传完成");

                       }

                });

           } 

       });   

      

       

         var _extensions = '3gp,mp4,rmvb,mov,avi,m4v';

         var _mimeTypes = 'video/*,audio/*,application/*';           

         var GUID = WebUploader.Base.guid();//一个GUID

         var uploader = WebUploader.create({

             swf: '__PUBLIC/webUploader/Uploader.swf',

             server: "{:url('Ajax/vupload')}",

             pick: '#picker',

             resize: false,

             chunked: true,//开始分片上传

             chunkSize: 5*1024*1024,//每一片的大小

             accept: {

                        title: '视频上传',

                        extensions: _extensions,

                        mimeTypes: _mimeTypes

                    },

            fileNumLimit: 1,//文件上传数量限制 

            threads: 1,

            formData: {

                 guid: GUID //自定义参数,待会儿解释

            }

         });

             

         uploader.on('uploadProgress', function (file, percentage) {

             $("#uploader .progress-bar").width(percentage * 100 + '%');

             $("#uploader .progress-bar").text(parseInt(percentage * 100) +"%");

         });

         uploader.on('uploadSuccess', function () {

             $("#uploader .progress-bar").removeClass('progress-bar-striped').removeClass('acti').removeClass('progress-bar-info').addClass('progress-bar-success');

             $("#uploader .state").html("上传成功...");

 

         });

         uploader.on('uploadError', function () {

             $("#uploader .progress-bar").removeClass('progress-bar-striped').removeClass('acti').removeClass('progress-bar-info').addClass('progress-bar-danger');

             $("#uploader .state").html("上传失败...");

         });

 

         $("#ctlBtn").click(function () {

             uploader.upload();

             $("#ctlBtn").text("上传");

             $('#ctlBtn').attr('disabled', 'disabled');

             $("#uploader .progress-bar").addClass('progress-bar-striped').addClass('active');

             $("#uploader .state").html("上传中...");

         });

         $('#pause').click(function () {

             uploader.stop(true);

             $('#ctlBtn').removeAttr('disabled');

             $("#ctlBtn").text("继续上传");

             $("#uploader .state").html("暂停中...");

             $("#uploader .progress-bar").removeClass('progress-bar-striped').removeClass('acti');

         });

    })

</script>

 

Ajax.php

<?php

// +----------------------------------------------------------------------

// | thinkpphp [ WE CAN DO IT MORE SIMPLE ]

// +----------------------------------------------------------------------

// | Copyright (c) 2018 rights reserved.

// +----------------------------------------------------------------------

// | Author: luyunoob <[email protected]>

// +----------------------------------------------------------------------

namespace app\admin\controller;

 

use think\Db;

use think\Cache;

use think\Session;

class Ajax

{

 

    //检测是否有断点

    public function check_breakpoint(){

        $post=request()->post();

        // 找出分片目录

        $dir=ROOT_PATH . 'data' . DS . 'upload'.DS.'video'.DS.$post['fileMd5'];

        if (file_exists($dir)) {

            // 扫描文件

            $block_info=scandir($dir);

            // 去除无用文件

            foreach ($block_info as $key => $block) {

                 if ($block == '.' || $block == '..') unset($block_info[$key]);

            }

            natsort($block_info);

            $end=end($block_info);

            if ($end>$post['chunk'] || $end==$post['chunk']) {

                echo json_encode(["ifExist"=>"1",'block_info'=>$end]);

            }

            

        }else{

            // 无断点

            echo json_encode(["ifExist"=>"0"]);

        }

 

    }

 

    // 视频上传

    public function vupload(){

        $post=request()->post();

        $dir=ROOT_PATH . 'data' . DS . 'upload'.DS.'video'.DS.$post['fileMd5'];

        $file = request()->file('file');

        if (file_exists($dir)) {

            $block_info=scandir($dir);

            natsort($block_info);

            // 去除无用文件

            foreach ($block_info as $key => $block) {

                 if ($block == '.' || $block == '..') unset($block_info[$key]);

            }

            $end=end($block_info);

            if ($post['chunk']>$end) {

                $info = $file->move($dir.DS.$post['chunk'],'');

 

            }

 

            if (isset($info)) {

                die('{"status":1,"msg":"正在上传请稍等"}');

            }else{

                die('{"status":0,"msg":"跳过 "}');

            }

        }else{

            if (empty($post['chunk'])) {

                $info = $file->move($dir.DS.'0','');

            }else{

                $info = $file->move($dir.DS.$post['chunk'],'');

            }

            if ($info) {

                die('{"status":1,"msg":"正在上传请稍等"}');

            }

        }

        

        

    }

 

    // 合并视频

    public function vupload_merge()

    {

        $post=request()->post();

        $dir=ROOT_PATH . 'data' . DS . 'upload'.DS.'video'.DS.$post['fileMd5'];

        $block_info = scandir($dir);

         // 除去无用文件

         foreach ($block_info as $key => $block) {

             if ($block == '.' || $block == '..') unset($block_info[$key]);

         }

         // 数组按照正常规则排序

         natsort($block_info);

         // 定义保存文件

         $save_file = ROOT_PATH . 'data' . DS . 'upload'.DS.'video'.DS.date('Ymd');

 

         // 没有?建立

         if (!file_exists($save_file)) {

            @mkdir ($save_file,0755,true);

         };

         $count=count($block_info);

            // 开始写入

            // 获取文件后缀

            $name=explode('.',$post['fileName']);

            $ext=end($name);

            $out = @fopen($save_file.DS.date('Ymdhis').'.'.$ext, "wb");

            $url='video'.DS.date('Ymd').DS.date('Ymdhis').'.'.$ext;

            // 增加文件锁

            if (flock($out, LOCK_EX)) {

                foreach ($block_info as $b) {

                    // 读取文件

                if (!$in = @fopen($dir.DS.$b.DS.$post['fileName'], "rb")) {

                    break;

                }

                    // 写入文件

                    while ($buff = fread($in, 4096)) {

                        fwrite($out, $buff);

                    }

 

                    @fclose($in);

                    @unlink($dir.'/'.$b);

                }

                flock($out, LOCK_UN);

            }

            @fclose($out);

            delete_dir_file($dir);

         echo json_encode(["code"=>"0",'url'=>$url]);//   }

  

}

common.php

<?php

/**

 * 循环删除目录和文件

 * @param string $dir_name

 * @return bool

 */

function delete_dir_file($dir_name)

{

    $result = false;

    if (is_dir($dir_name)) {

        if ($handle = opendir($dir_name)) {

            while (false !== ($item = readdir($handle))) {

                if ($item != '.' && $item != '..') {

                    if (is_dir($dir_name . DS . $item)) {

                        delete_dir_file($dir_name . DS . $item);

                    } else {

                        unlink($dir_name . DS . $item);

                    }

                }

            }

            closedir($handle);

            if (rmdir($dir_name)) {

                $result = true;

            }

        }

    }

 

    return $result;

}

 

?>

总结:

以上就是PHP上传超大文件的实现方式,对于这种超大文件的上传主要思路就是化整为零,把大的文件拆分成小的文件进行上传就可以了,这里面主要还涉及到断点续传等问题,好了,如果你也有遇到上传超大文件超时等问题,可以参考一下这篇文章的实现思路(完)。

 

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/20/php%e5%a6%82%e4%bd%95%e4%b8%8a%e4%bc%a0%e8%b6%85%e5%a4%a7%e6%96%87%e4%bb%b6/

欢迎入群一起讨论

 

 

标签:info,超大,block,file,PHP,上传,DS,dir
From: https://www.cnblogs.com/songsu/p/17717660.html

相关文章

  • 整理php防注入和XSS攻击通用过滤
    对网站发动XSS攻击的方式有很多种,仅仅使用php的一些内置过滤函数是对付不了的,即使你将filter_var,mysql_real_escape_string,htmlentities,htmlspecialchars,strip_tags这些函数都使用上了也不一定能保证绝对的安全。那么如何预防XSS注入?主要还是需要在用户数据过滤方面得考虑......
  • pikachu的文件上传
    1.单纯的前端js验证,我们直接在浏览器禁用即可。或者可以通过上传图片后缀再抓包修改为php的方式 2.这个是通过验证包中的Content-Type:进行,只需要抓包之后更改即可(图片中没改) 3.这个是通过检测上传文件的文件头进行识别,我们可以选择在php文件前加上图片的码或者直接使用co......
  • 2022最新上传ipa到appstore的步骤说明
    我们平时在开发原生的iosapp的时候,有苹果电脑在手,上传ipa文件到苹果开发者中心比较简单,直接在xcode上就可以实现了。但是现在大多数人开发app不再是用原生框架开发了,也没有苹果电脑。很多朋友们选择了跨平台的H5技术来开发app,真正做到实现一种语法到处运行的场景。现在比较热的框......
  • Appuploader工具让ipa上传到App Store 的最新流程和步骤
    苹果官方提供的工具xcode上架ipa非常复杂麻烦。用appuploader可以在mac和windows上制作管理证书,无需钥匙串工具条件:1.以Windows为例,创建app打包ios需要的证书和描述文件      2.准备好一个苹果开发者账号(如果没有到苹果官网注册一个即可)目录 总体流程:1.创建Appid......
  • 如何上传专用密码和登录iCloud教程
    步骤1:在AppUploader这个页面中,依次按照要求操作。步骤2:进入管理您的AppleID页面,然后点击红圈中的更多。步骤3:根据步骤操作,即可生成专用密码。步骤4:在App Uploader页面输入前面生成的专用密码即可登录成功。步骤五:在iCloud页面进行登录操作。步骤六:找到AppID。 步骤七:输入App......
  • 上传20M的ipa ,使用Appuploader工具只有2分钟左右即可上传成功
    1.如果是新账号(免费账号),应该在第二个步骤中勾选“未支付688选项”,并且还需要安装icloud,登陆iCloud链接:下载iCloud 2.官网下载最新的Hbuilderx。 3.打包ipa(包含manifest.json的vue项目),点击详情设置,如图标,描述等,设置完成后,点击保存。 4.菜单项点击‘发行->云打包-打原生安装包’,......
  • 谈一谈 IPA 上传到 App Store Connect 的几种方法
    1、前言关于上传ipa包到AppStoreConnect的方法,相信有iOS开发经验的同学,一定知道完成App开发后,一般都是用Xcode的Archive打包后上传到苹果后台。所以,这个就是今天要写的水文?显示不是吧!答案肯定不是啊,本文将给大家一个相对全面介绍。苹果开发的知识点非常多,官方文档也......
  • iOS APP上架App Store其中一个步骤就是要把ipa文件上传到App Store
    下面进行步骤介绍!利用Appuploader这个软件,可以在Windows、Linux或Mac系统中申请ios和上传IPA到AppStoreConnect。非常的方便,没有Mac也可以用Appuploader在Windows电脑上传ipa到AppStoreConnect后台。Appuploader下载链接1、因为苹果开发者账号现在都开通了双重认证,所以需要......
  • 2022苹果AppStore应用商店上传与APP上传流程必看(基础篇)
    如果App想要成功出现在商店中,开发者还需要经过上传操作和苹果公司的严格审核。同时,在App上架AppStore时,如有违规,将受到苹果公司的处罚。此外,优质app也会得到苹果的推荐,通过优质曝光和苹果官方背书获得更多用户增长。本章将对苹果的上传、审核、推荐、惩罚四大机制进行说明。第三......
  • 大文件上传如何做断点续传?
    是什么不管怎样简单的需求,在量级达到一定层次时,都会变得异常复杂文件上传简单,文件变大就复杂上传大文件时,以下几个变量会影响我们的用户体验服务器处理数据的能力请求超时网络波动上传时间会变长,高频次文件上传失败,失败后又需要重新上传等等为了解决上述问题,我们需要对大文件......