静态文件 需要切片传输的看这个

陈品忠

为什么要这样搞 因为很多视频 不可能 一次传输 需要切片 不然会断流
用nginx 就不会有这个问题 这个是 原生方案

中间件实现

<?php
/**
 * This file is part of webman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
 */

namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;

/**
 * Class StaticFile
 * @package app\middleware
 */
class StaticFile implements MiddlewareInterface
{
    public function process(Request $request, callable $next): Response
    {
        $path = ltrim($request->path(), '/');
        $public_dir = config('app.public_path');
        $file = $public_dir . '/' . $path;

        //不是文件 不需要 这个中间件处理
        if (!is_file($file))  return $next($request);

        // 禁止隐藏文件
        if (strpos($path, '/.') !== false) {
            return new Response(403, [], '<h1>403 forbidden</h1>');
        }

        $mime_type = mime_content_type($file) ?: 'application/octet-stream';//文件类型

        //如果浏览器要切片  就返回切片内容
        // 解析 Range
        $range_header = $request->header('Range', '');
        if(!empty($range_header)){
            $size = filesize($file);//文件大小
            //大文件切片返回  这个是针对视频传输的
            $start = 0;
            $end = $size - 1;

            if (preg_match('/bytes=(\d+)-(\d*)/', $range_header, $matches)) {
                $start = intval($matches[1]);
                if ($matches[2] !== '') {
                    $end = intval($matches[2]);
                }
            }

            // ⭐ 固定每次发送的最大大小
            $max_chunk = 5 * 1024 * 1024; // 5MB
            if (($end - $start + 1) > $max_chunk) {
                $end = $start + $max_chunk - 1;
                if ($end >= $size) $end = $size - 1;
            }
            $length = $end - $start + 1;
            $fp = fopen($file, 'rb');
            fseek($fp, $start);
            $body = fread($fp, $length);
            fclose($fp);
            return new Response(
                206, // Partial Content
                [
                    'Content-Type' => $mime_type,
                    'Accept-Ranges' => 'bytes',
                    'Content-Range' => "bytes $start-$end/$size",
                    'Connection' => 'keep-alive',
                ],
                $body
            );
        }

        //返回文件内容
        return new Response(
            200, // Partial Content
            [
                'Content-Type' => $mime_type,
                'Accept-Ranges' => 'bytes',
                'Connection' => 'keep-alive',
            ],
            file_get_contents($file)
        );
    }
}

配置文件 需要修改
config->static

<?php
/**
 * This file is part of webman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * Static file settings
 */
return [
    'enable' => true,
    'middleware' => [// Static file Middleware
        app\middleware\StaticFile::class,
    ],
];
168 1 6
1个回答

TM

点赞,很合适内部文件存储

  • 暂无评论
🔝