当前位置:首页>php>PHP高性能Webman框架FFmpeg实现实时视频流HLS

PHP高性能Webman框架FFmpeg实现实时视频流HLS

  • 2026-06-30 10:17:48
PHP高性能Webman框架FFmpeg实现实时视频流HLS

简介

本文将基于 PHP Webman 高性能框架构建支持 HLS(HTTP 实时流媒体) 的视频流媒体服务器基础架构。我们将通过 FFmpeg 将上传的视频进行转码以及分段处理(将一个视频根据配置的秒数分成多段视频),实现真正的按需加载、实时播放。

什么是 HLS?

HLS(HTTP Live Streaming)是苹果公司提出的基于 HTTP 的流媒体网络传输协议。它的工作原理是将整个流分成一系列小的基于 HTTP 的文件来下载,每次只下载当前播放需要的分片。核心组成:

  • .m3u8 播放列表文件:索引文件,记录了所有分片的信息和顺序
  • .ts 分片文件:实际的视频数据片段,每个片段几秒钟

什么是 FFmpeg?

FFmpeg 是全球领先的多媒体框架工具,具备解码、编码、转码、复用(封装)、解复用(解封装)、流传输、滤镜处理以及播放几乎所有多媒体内容的能力。它支持从最冷门的老旧格式到最前沿的技术标准,具有极强的可移植性,能够在 Linux、macOS、Windows 等各类操作系统上编译运行。

实战案例

安装 FFmpeg

从下面地址下载 FFmpeg(根据你的平台选择,本文以 Linux 为例):

# Ubuntu/Debiansudo apt updatesudo apt install ffmpeg# CentOS/RHELsudo yum install epel-releasesudo yum install ffmpeg# macOSbrew install ffmpeg# Windows - 下载地址# https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip

安装完成后,验证安装:

ffmpeg -version

创建 Webman 项目

composer create-project workerman/webman video-streamingcd video-streaming

项目结构:

video-streaming/├── app/│   ├── controller/│   │   └── VideoController.php│   └── view/│       └── player.html├── config/│   └── route.php├── public/└── runtime/    └── videos/          # 视频存储目录        └── hls/         # HLS转码输出目录

FFmpeg HLS 转码命令

我们将使用以下命令将视频转为 HLS 格式:

ffmpeg -i input.mp4 \  -profile:v baseline \  -level 3.0 \  -start_number 0 \  -hls_time 6 \  -hls_list_size 0 \  -f hls \  ./index.m3u8

参数说明:

参数
说明
-i
输入文件路径,指定要转码的输入视频文件
-profile:v baseline
视频编码配置,使用 H.264 的 Baseline Profile,适合移动设备和低延迟场景(不包含 B 帧,兼容性更好)
-level 3.0
指定 H.264 编码级别为 3.0,限制分辨率、帧率等参数(例如最大支持 720p)
-start_number 0
生成的 HLS 分段文件(.ts)从 0.ts 开始编号
-hls_time 6
每个分段(.ts 文件)的时长为 6 秒
-hls_list_size 0
在 .m3u8 播放列表中保留所有分段(0 表示不轮替,适合点播;直播通常设为 5 或 7)
-f hls
强制输出格式为 HLS
./index.m3u8
输出文件名
执行后生成的文件结构:
output/├── index.m3u8├── index0.ts├── index1.ts├── index2.ts└── ...

生成的 index.m3u8 文件内容示例:

#EXTM3U#EXT-X-VERSION:3#EXT-X-TARGETDURATION:9#EXT-X-MEDIA-SEQUENCE:0#EXTINF:8.808800,index0.ts#EXTINF:5.605600,index1.ts#EXTINF:5.605600,index2.ts#EXTINF:6.306300,index3.ts#EXTINF:3.703700,index4.ts#EXT-X-ENDLIST

2.2 上传视频并转码

配置路由

编辑 config/route.php

<?phpuseWebman\Route;// 视频上传接口Route::post('/videos/upload', [app\controller\VideoController::class, 'upload']);// 视频列表接口Route::get('/videos/list', [app\controller\VideoController::class, 'list']);// 视频删除接口Route::delete('/videos/delete/{id}', [app\controller\VideoController::class, 'delete']);// 播放器页面Route::get('/player', [app\controller\VideoController::class, 'player']);// 关闭默认路由Route::disableDefaultRoute();

控制器实现

创建 app/controller/VideoController.php

<?phpnamespaceapp\controller;usesupport\Request;usesupport\Response;classVideoController{// 视频存储根目录private string $storagePath = runtime_path() . 'videos';// HLS输出目录private string $hlsOutputPath = runtime_path() . 'videos/hls';// FFmpeg可执行文件路径(根据实际安装路径修改)private string $ffmpegPath = 'ffmpeg';// 允许的视频格式privatearray $allowedExtensions = ['mp4''avi''mov''mkv''flv''wmv'];publicfunction__construct(){// 确保目录存在if (!is_dir($this->storagePath)) {            mkdir($this->storagePath, 0755true);        }if (!is_dir($this->hlsOutputPath)) {            mkdir($this->hlsOutputPath, 0755true);        }    }/**     * 上传视频并转码为HLS     */publicfunctionupload(Request $request)Response{        $file = $request->file('file');if (!$file || !$file->isValid()) {return json(['code' => 400'msg' => '请上传有效的视频文件']);        }// 验证文件扩展名        $extension = strtolower($file->getUploadExtension());if (!in_array($extension, $this->allowedExtensions)) {return json(['code' => 400'msg' => '不支持的视频格式,允许的格式:' . implode(', '$this->allowedExtensions)            ]);        }// 验证文件大小(限制500MB)        $maxSize = 500 * 1024 * 1024;if ($file->getSize() > $maxSize) {return json(['code' => 400'msg' => '文件大小不能超过500MB']);        }// 生成唯一ID作为视频标识        $videoId = uniqid('vid_'true);// 保存原始文件        $inputFileName = $videoId . '.' . $extension;        $inputFilePath = $this->storagePath . '/' . $inputFileName;        $file->move($inputFilePath);// 创建HLS输出目录        $outputDir = $this->hlsOutputPath . '/' . $videoId;if (!is_dir($outputDir)) {            mkdir($outputDir, 0755true);        }// 构建FFmpeg转码命令        $outputM3u8 = $outputDir . '/index.m3u8';        $ffmpegCmd = sprintf('%s -i %s -profile:v baseline -level 3.0 -start_number 0 -hls_time 6 -hls_list_size 0 -f hls %s',$this->ffmpegPath,            escapeshellarg($inputFilePath),            escapeshellarg($outputM3u8)        );// 执行转码命令        $output = [];        $returnVar = 0;        exec($ffmpegCmd . ' 2>&1', $output, $returnVar);if ($returnVar !== 0) {// 转码失败,清理文件            @unlink($inputFilePath);$this->deleteDirectory($outputDir);return json(['code' => 500'msg' => '视频转码失败','error' => implode("\n", $output)            ]);        }// 生成缩略图        $thumbnailPath = $outputDir . '/thumbnail.jpg';$this->generateThumbnail($inputFilePath, $thumbnailPath);// 保存视频信息到数据库(这里用JSON文件模拟)$this->saveVideoInfo($videoId, ['id' => $videoId,'original_name' => $file->getUploadName(),'file_size' => $file->getSize(),'format' => $extension,'upload_time' => date('Y-m-d H:i:s'),'hls_path' => '/streaming/hls/' . $videoId . '/index.m3u8','thumbnail' => '/streaming/hls/' . $videoId . '/thumbnail.jpg',        ]);return json(['code' => 200'msg' => '上传成功并转码为HLS格式','data' => ['video_id' => $videoId,'hls_url' => '/streaming/hls/' . $videoId . '/index.m3u8','thumbnail' => '/streaming/hls/' . $videoId . '/thumbnail.jpg',            ]        ]);    }/**     * 获取视频列表     */publicfunctionlist(Request $request)Response{        $videoInfoPath = $this->storagePath . '/video_info.json';        $videos = [];if (file_exists($videoInfoPath)) {            $videos = json_decode(file_get_contents($videoInfoPath), true) ?: [];        }return json(['code' => 200'data' => array_values($videos)]);    }/**     * 删除视频     */publicfunctiondelete(Request $request, $id)Response{        $videoInfoPath = $this->storagePath . '/video_info.json';        $videos = [];if (file_exists($videoInfoPath)) {            $videos = json_decode(file_get_contents($videoInfoPath), true) ?: [];        }if (!isset($videos[$id])) {return json(['code' => 404'msg' => '视频不存在']);        }        $videoInfo = $videos[$id];// 删除原始文件        $originalFile = $this->storagePath . '/' . $id . '.' . $videoInfo['format'];if (file_exists($originalFile)) {            @unlink($originalFile);        }// 删除HLS输出目录        $hlsDir = $this->hlsOutputPath . '/' . $id;if (is_dir($hlsDir)) {$this->deleteDirectory($hlsDir);        }// 从列表中移除unset($videos[$id]);        file_put_contents($videoInfoPath, json_encode($videos, JSON_PRETTY_PRINT));return json(['code' => 200'msg' => '删除成功']);    }/**     * 播放器页面     */publicfunctionplayer(Request $request)Response{return view('player');    }/**     * 生成缩略图     */privatefunctiongenerateThumbnail(string $inputFile, string $outputFile)bool{// 从第5秒截取一帧作为缩略图        $cmd = sprintf('%s -i %s -ss 00:00:05 -vframes 1 -q:v 2 %s',$this->ffmpegPath,            escapeshellarg($inputFile),            escapeshellarg($outputFile)        );        exec($cmd . ' 2>&1', $output, $returnVar);return $returnVar === 0;    }/**     * 保存视频信息     */privatefunctionsaveVideoInfo(string $videoId, array $info)void{        $videoInfoPath = $this->storagePath . '/video_info.json';        $videos = [];if (file_exists($videoInfoPath)) {            $videos = json_decode(file_get_contents($videoInfoPath), true) ?: [];        }        $videos[$videoId] = $info;        file_put_contents($videoInfoPath, json_encode($videos, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));    }/**     * 递归删除目录     */privatefunctiondeleteDirectory(string $dir)bool{if (!is_dir($dir)) {returnfalse;        }        $items = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),            \RecursiveIteratorIterator::CHILD_FIRST        );foreach ($items as $item) {if ($item->isDir()) {                rmdir($item->getRealPath());            } else {                unlink($item->getRealPath());            }        }return rmdir($dir);    }}

配置静态资源访问

为了让前端能访问转码后的 .m3u8 和 .ts 文件,需要配置静态资源路径。 编辑 config/static.php(如果没有则创建):

<?phpreturn [// 静态文件路由映射'map' => ['/streaming' => runtime_path() . 'videos',    ],];

或者通过中间件方式更灵活地控制访问,创建 app/middleware/StreamingAccess.php

<?phpnamespaceapp\middleware;useWebman\MiddlewareInterface;useWebman\Http\Response;useWebman\Http\Request;classStreamingAccessimplementsMiddlewareInterface{publicfunctionprocess(Request $request, callable $handler)Response{        $path = $request->path();// 只允许访问hls目录下的文件if (strpos($path, '/streaming/hls/') === 0) {            $filePath = runtime_path() . 'videos' . substr($path, strlen('/streaming'));if (file_exists($filePath) && is_file($filePath)) {                $extension = pathinfo($filePath, PATHINFO_EXTENSION);                $contentTypes = ['m3u8' => 'application/vnd.apple.mpegurl','ts' => 'video/mp2t','jpg' => 'image/jpeg','png' => 'image/png',                ];                $contentType = $contentTypes[$extension] ?? 'application/octet-stream';returnnew Response(200, ['Content-Type' => $contentType,'Cache-Control' => 'public, max-age=3600','Access-Control-Allow-Origin' => '*',                ], file_get_contents($filePath));            }        }return $handler($request);    }}

在 config/middleware.php 中注册中间件:

<?phpreturn ['' => [        app\middleware\StreamingAccess::class,    ],];

2.3 播放转码后的视频

下载 hls.js

从 CDN 下载 hls.js 播放器库:

https://cdn.jsdelivr.net/npm/hls.js@latest

将文件保存到 public/hls.js

创建播放器页面

创建 app/view/player.html

<!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>实时视频流技术 - Webman + FFmpeg HLS</title><scriptsrc="/hls.js"></script><style>        * {margin0;padding0;box-sizing: border-box;        }body {font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;background#0f0f0f;color#fff;min-height100vh;        }.container {max-width1200px;margin0 auto;padding20px;        }header {text-align: center;padding30px0;border-bottom1px solid #333;margin-bottom30px;        }headerh1 {font-size32px;margin-bottom10px;backgroundlinear-gradient(135deg, #667eea 0%, #764ba2 100%);-webkit-background-clip: text;-webkit-text-fill-color: transparent;        }headerp {color#888;font-size16px;        }.upload-section {background#1a1a1a;border-radius12px;padding30px;margin-bottom30px;border2px dashed #333;transition: border-color 0.3s;        }.upload-section:hover {border-color#667eea;        }.upload-sectionh2 {margin-bottom20px;font-size22px;        }.upload-form {display: flex;gap15px;align-items: center;flex-wrap: wrap;        }.file-input-wrapper {position: relative;flex1;min-width200px;        }.file-input-wrapperinput[type="file"] {width100%;padding12px;background#252525;border1px solid #444;border-radius8px;color#fff;cursor: pointer;        }.upload-btn {padding12px30px;backgroundlinear-gradient(135deg, #667eea 0%, #764ba2 100%);border: none;border-radius8px;color#fff;font-size16px;font-weight600;cursor: pointer;transition: opacity 0.3s;        }.upload-btn:hover {opacity0.9;        }.upload-btn:disabled {opacity0.5;cursor: not-allowed;        }.progress-bar {width100%;height4px;background#252525;border-radius2px;margin-top15px;display: none;        }.progress-bar.progress {height100%;backgroundlinear-gradient(90deg, #667eea 0%, #764ba2 100%);border-radius2px;width0%;transition: width 0.3s;        }.video-grid {display: grid;grid-template-columnsrepeat(auto-fill, minmax(280px1fr));gap20px;margin-bottom30px;        }.video-card {background#1a1a1a;border-radius12px;overflow: hidden;cursor: pointer;transition: transform 0.3s, box-shadow 0.3s;        }.video-card:hover {transformtranslateY(-5px);box-shadow010px30pxrgba(1021262340.2);        }.video-thumbnail {width100%;height180px;object-fit: cover;background#252525;        }.video-info {padding15px;        }.video-infoh3 {font-size16px;margin-bottom8px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;        }.video-meta {font-size13px;color#888;display: flex;justify-content: space-between;        }.player-section {background#1a1a1a;border-radius12px;overflow: hidden;display: none;        }.player-header {display: flex;justify-content: space-between;align-items: center;padding15px20px;background#141414;border-bottom1px solid #333;        }.player-headerh2 {font-size18px;        }.close-btn {background: none;border: none;color#888;font-size24px;cursor: pointer;transition: color 0.3s;        }.close-btn:hover {color#fff;        }video {width100%;max-height70vh;display: block;background#000;        }.video-stats {padding15px20px;display: flex;gap20px;font-size13px;color#888;        }.empty-state {text-align: center;padding60px20px;color#666;        }.empty-statesvg {width80px;height80px;margin-bottom20px;opacity0.3;        }.notification {position: fixed;top20px;right20px;padding15px25px;border-radius8px;color#fff;font-weight500;z-index1000;transformtranslateX(120%);transition: transform 0.3s;        }.notification.show {transformtranslateX(0);        }.notification.success {background#10b981;        }.notification.error {background#ef4444;        }.notification.info {background#3b82f6;        }@media (max-width:768px) {.container {padding15px;            }headerh1 {font-size24px;            }.upload-form {flex-direction: column;            }.video-grid {grid-template-columns1fr;            }        }</style></head><body><divclass="container"><header><h1>Webman + FFmpeg 实时视频流</h1><p>基于HLS协议的视频流媒体服务器</p></header><sectionclass="upload-section"><h2>📤 上传视频</h2><divclass="upload-form"><divclass="file-input-wrapper"><inputtype="file"id="videoFile"accept="video/*"></div><buttonclass="upload-btn"id="uploadBtn"disabled>上传并转码</button></div><divclass="progress-bar"id="progressBar"><divclass="progress"id="progress"></div></div></section><sectionid="videoList"><divclass="empty-state"id="emptyState"><svgxmlns="http://www.w3.org/2000/svg"fill="none"viewBox="0 0 24 24"stroke="currentColor"><pathstroke-linecap="round"stroke-linejoin="round"stroke-width="1"d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" /></svg><p>暂无视频,请上传视频文件</p></div><divclass="video-grid"id="videoGrid"></div></section><sectionclass="player-section"id="playerSection"><divclass="player-header"><h2id="playerTitle">正在播放</h2><buttonclass="close-btn"id="closePlayer">&times;</button></div><videoid="videoPlayer"controlsautoplay></video><divclass="video-stats"><spanid="videoResolution">分辨率: --</span><spanid="videoDuration">时长: --</span><spanid="videoSegments">分片数: --</span></div></section></div><divclass="notification"id="notification"></div><script>// API基础URLconst API_BASE = '';// DOM元素const videoFile = document.getElementById('videoFile');const uploadBtn = document.getElementById('uploadBtn');const progressBar = document.getElementById('progressBar');const progress = document.getElementById('progress');const videoGrid = document.getElementById('videoGrid');const emptyState = document.getElementById('emptyState');const playerSection = document.getElementById('playerSection');const videoPlayer = document.getElementById('videoPlayer');const playerTitle = document.getElementById('playerTitle');const closePlayer = document.getElementById('closePlayer');const notification = document.getElementById('notification');let hls = null;let currentVideoInfo = null;// 显示通知functionshowNotification(message, type = 'info'{            notification.textContent = message;            notification.className = 'notification ' + type + ' show';            setTimeout(() => {                notification.classList.remove('show');            }, 3000);        }// 文件选择事件        videoFile.addEventListener('change'function() {            uploadBtn.disabled = !this.files.length;        });// 上传视频        uploadBtn.addEventListener('click'asyncfunction() {const file = videoFile.files[0];if (!file) return;const formData = new FormData();            formData.append('file', file);            uploadBtn.disabled = true;            uploadBtn.textContent = '上传中...';            progressBar.style.display = 'block';try {const xhr = new XMLHttpRequest();                xhr.upload.addEventListener('progress', (e) => {if (e.lengthComputable) {const percentComplete = (e.loaded / e.total) * 100;                        progress.style.width = percentComplete + '%';                    }                });                xhr.addEventListener('load'function() {if (xhr.status === 200) {const response = JSON.parse(xhr.responseText);if (response.code === 200) {                            showNotification('上传成功,正在转码...''success');// 转码需要时间,延迟刷新列表                            setTimeout(loadVideoList, 3000);                        } else {                            showNotification(response.msg || '上传失败''error');                        }                    } else {                        showNotification('上传失败''error');                    }                    resetUploadForm();                });                xhr.addEventListener('error'function() {                    showNotification('网络错误''error');                    resetUploadForm();                });                xhr.open('POST', API_BASE + '/videos/upload');                xhr.send(formData);            } catch (error) {                showNotification('上传异常: ' + error.message, 'error');                resetUploadForm();            }        });// 重置上传表单functionresetUploadForm() {            uploadBtn.disabled = false;            uploadBtn.textContent = '上传并转码';            progressBar.style.display = 'none';            progress.style.width = '0%';            videoFile.value = '';        }// 加载视频列表asyncfunctionloadVideoList() {try {const response = await fetch(API_BASE + '/videos/list');const result = await response.json();if (result.code === 200 && result.data.length > 0) {                    emptyState.style.display = 'none';                    renderVideoGrid(result.data);                } else {                    emptyState.style.display = 'block';                    videoGrid.innerHTML = '';                }            } catch (error) {console.error('加载视频列表失败:', error);            }        }// 渲染视频网格functionrenderVideoGrid(videos{            videoGrid.innerHTML = videos.map(video =>`                <div class="video-card" onclick="playVideo('${video.id}', '${video.original_name}')">                    <img class="video-thumbnail"                          src="${video.thumbnail}                         alt="${video.original_name}"                         onerror="this.src='data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 300 180%22%3E%3Crect fill=%22%23252525%22 width=%22300%22 height=%22180%22/%3E%3Ctext fill=%22%23666%22 font-size=%2220%22 x=%2250%25%22 y=%2250%25%22 text-anchor=%22middle%22 dy=%22.3em%22%3E无缩略图%3C/text%3E%3C/svg%3E'">                    <div class="video-info">                        <h3 title="${video.original_name}">${video.original_name}</h3>                        <div class="video-meta">                            <span>${formatFileSize(video.file_size)}</span>                            <span>${video.upload_time}</span>                        </div>                    </div>                </div>            `).join('');        }// 播放视频functionplayVideo(videoId, title{const url = API_BASE + '/streaming/hls/' + videoId + '/index.m3u8';            playerTitle.textContent = '正在播放: ' + title;            playerSection.style.display = 'block';// 销毁之前的HLS实例if (hls) {                hls.destroy();            }if (Hls.isSupported()) {                hls = new Hls({maxBufferLength30,maxMaxBufferLength60,                });                hls.loadSource(url);                hls.attachMedia(videoPlayer);                hls.on(Hls.Events.MANIFEST_PARSED, function(event, data{                    videoPlayer.play();                    updateVideoStats(data);                });                hls.on(Hls.Events.ERROR, function(event, data{if (data.fatal) {switch (data.type) {case Hls.ErrorTypes.NETWORK_ERROR:console.error('网络错误,尝试恢复...');                                hls.startLoad();break;case Hls.ErrorTypes.MEDIA_ERROR:console.error('媒体错误,尝试恢复...');                                hls.recoverMediaError();break;default:console.error('无法恢复的错误');                                hls.destroy();                                showNotification('播放失败''error');break;                        }                    }                });            } elseif (videoPlayer.canPlayType('application/vnd.apple.mpegurl')) {// Safari原生支持HLS                videoPlayer.src = url;                videoPlayer.addEventListener('loadedmetadata'function() {                    videoPlayer.play();                });            } else {                showNotification('您的浏览器不支持HLS播放''error');            }// 滚动到播放器位置            playerSection.scrollIntoView({ behavior'smooth' });        }// 更新视频统计信息functionupdateVideoStats(data{// 这些信息可以从API获取,这里简化处理document.getElementById('videoSegments').textContent = '分片数: ' + (data.levels && data.levels[0] ? data.levels[0].details.fragments.length : '--');        }// 关闭播放器        closePlayer.addEventListener('click'function() {            playerSection.style.display = 'none';if (hls) {                hls.destroy();                hls = null;            }            videoPlayer.pause();            videoPlayer.src = '';        });// 格式化文件大小functionformatFileSize(bytes{if (bytes === 0return'0 B';const k = 1024;const sizes = ['B''KB''MB''GB'];const i = Math.floor(Math.log(bytes) / Math.log(k));returnparseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];        }// 初始化加载视频列表        loadVideoList();</script></body></html>

2.4 测试运行

启动 Webman 服务

cd video-streamingphp windows.php  # Windows# 或php start.php start  # Linux

默认监听 http://0.0.0.0:8787

测试上传接口

使用 Postman 或 curl 测试:

curl -X POST http://localhost:8787/videos/upload \  -F "file=@/path/to/your/video.mp4"

响应示例:

{"code"200,"msg""上传成功并转码为HLS格式","data": {"video_id""vid_648f5a2b3c1d4","hls_url""/streaming/hls/vid_648f5a2b3c1d4/index.m3u8","thumbnail""/streaming/hls/vid_648f5a2b3c1d4/thumbnail.jpg"    }}

访问播放器

打开浏览器访问:http://localhost:8787/player

3. 进阶功能

3.1 生成缩略图

在视频列表中展示缩略图是常见需求,FFmpeg 可以轻松实现:

ffmpeg -i input.mp4 -ss 00:00:05 -vframes 1 -q:v 2 thumbnail.jpg

参数说明:

参数
说明
-i
输入视频文件
-ss 00:00:05
从第5秒开始提取
-vframes 1
只提取1帧
-q:v 2
控制输出质量(1-31,值越小质量越高,2通常足够)
thumbnail.jpg
输出缩略图文件名(支持.jpg, .png, .webp等)

3.2 多分辨率自适应

为不同网络条件提供多分辨率版本,修改转码命令:

// 在 VideoController.php 的 upload 方法中,替换转码命令为多分辨率版本$ffmpegCmd = sprintf('%s -i %s ' .'-map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 ' .'-c:v libx264 -c:a aac ' .'-filter:v:0 "scale=1920:1080" -b:v:0 5000k -maxrate:v:0 5350k -bufsize:v:0 7500k ' .'-filter:v:1 "scale=1280:720" -b:v:1 2800k -maxrate:v:1 2996k -bufsize:v:1 4200k ' .'-filter:v:2 "scale=854:480" -b:v:2 1400k -maxrate:v:2 1498k -bufsize:v:2 2100k ' .'-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" ' .'-master_pl_name master.m3u8 ' .'-f hls -hls_time 6 -hls_list_size 0 ' .'-hls_segment_filename "%s/%%v/segment_%%03d.ts" ' .'%s/%%v/index.m3u8',$this->ffmpegPath,    escapeshellarg($inputFilePath),    escapeshellarg($outputDir),    escapeshellarg($outputDir));

3.3 异步转码队列

对于大文件,同步转码会导致请求超时。可以使用 Webman 的自定义进程实现异步队列: 创建 app/process/TranscodeQueue.php

<?phpnamespaceapp\process;useWorkerman\Connection\TcpConnection;useWebman\Config;classTranscodeQueue{privatearray $queue = [];private bool $processing = false;publicfunctiononWorkerStart()void{// 启动队列处理$this->processQueue();    }publicfunctiononMessage(TcpConnection $connection, $data)void{        $task = json_decode($data, true);if ($task && isset($task['type']) && $task['type'] === 'transcode') {$this->queue[] = $task;            $connection->send(json_encode(['status' => 'queued''position' => count($this->queue)]));if (!$this->processing) {$this->processQueue();            }        }    }privatefunctionprocessQueue()void{if ($this->processing || empty($this->queue)) {return;        }$this->processing = true;        $task = array_shift($this->queue);// 执行转码任务$this->executeTranscode($task);$this->processing = false;// 继续处理下一个任务if (!empty($this->queue)) {$this->processQueue();        }    }privatefunctionexecuteTranscode(array $task)void{        $ffmpegCmd = sprintf('%s -i %s -profile:v baseline -level 3.0 -start_number 0 -hls_time 6 -hls_list_size 0 -f hls %s','ffmpeg',            escapeshellarg($task['input_file']),            escapeshellarg($task['output_file'])        );        exec($ffmpegCmd . ' 2>&1', $output, $returnVar);// 更新任务状态到数据库或缓存// ...    }}

在 config/process.php 中注册:

<?phpreturn ['transcode_queue' => ['handler' => app\process\TranscodeQueue::class,'listen' => 'text://0.0.0.0:8788','count' => 1,  // 单进程处理,避免并发问题    ],];

3.4 视频加密(DRM)

为视频添加 AES-128 加密,保护内容安全:

// 生成加密密钥$encryptionKey = random_bytes(16);$keyPath = $outputDir . '/enc.key';file_put_contents($keyPath, $encryptionKey);// 生成密钥信息文件$keyInfoPath = $outputDir . '/enc.keyinfo';$keyInfoContent = $keyPath . "\n";$keyInfoContent .= $keyPath . "\n";file_put_contents($keyInfoPath, $keyInfoContent);// 修改FFmpeg命令,添加加密参数$ffmpegCmd = sprintf('%s -i %s -profile:v baseline -level 3.0 ' .'-hls_key_info_file %s ' .'-start_number 0 -hls_time 6 -hls_list_size 0 -f hls %s',$this->ffmpegPath,    escapeshellarg($inputFilePath),    escapeshellarg($keyInfoPath),    escapeshellarg($outputM3u8));

3.5 实时直播流

虽然本文主要介绍点播(VOD),但 FFmpeg 也支持实时直播流转 HLS:

// 接收RTMP直播流并转为HLS$ffmpegCmd = sprintf('%s -listen 1 -i rtmp://0.0.0.0:1935/live/stream ' .'-c:v libx264 -preset veryfast -tune zerolatency ' .'-c:a aac -ar 44100 -b:a 128k ' .'-f hls -hls_time 4 -hls_list_size 6 -hls_flags delete_segments ' .'-hls_segment_filename "%s/segment_%%03d.ts" %s',$this->ffmpegPath,    escapeshellarg($outputDir),    escapeshellarg($outputDir . '/live.m3u8'));

4. 完整项目结构

最终的项目文件结构:

video-streaming/├── app/│   ├── controller/│   │   └── VideoController.php      # 视频控制器│   ├── middleware/│   │   └── StreamingAccess.php      # 流媒体访问中间件│   ├── process/│   │   └── TranscodeQueue.php       # 异步转码队列│   └── view/│       └── player.html              # 播放器页面├── config/│   ├── middleware.php               # 中间件配置│   ├── process.php                  # 自定义进程配置│   ├── route.php                    # 路由配置│   └── static.php                   # 静态资源配置├── public/│   └── hls.js                       # HLS播放器库├── runtime/│   └── videos/                      # 视频存储(运行时生成)│       ├── video_info.json          # 视频信息数据库│       └── hls/                     # HLS转码输出├── composer.json└── start.php                        # 启动文件

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 20:45:54 HTTP/2.0 GET : https://f.mffb.com.cn/a/492597.html
  2. 运行时间 : 0.283418s [ 吞吐率:3.53req/s ] 内存消耗:4,791.50kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=948ea5dd195372f72860db8412dd75c1
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000933s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001263s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000660s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.003062s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001199s ]
  6. SELECT * FROM `set` [ RunTime:0.000527s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001250s ]
  8. SELECT * FROM `article` WHERE `id` = 492597 LIMIT 1 [ RunTime:0.007888s ]
  9. UPDATE `article` SET `lasttime` = 1783082754 WHERE `id` = 492597 [ RunTime:0.021721s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.005147s ]
  11. SELECT * FROM `article` WHERE `id` < 492597 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000668s ]
  12. SELECT * FROM `article` WHERE `id` > 492597 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000459s ]
  13. SELECT * FROM `article` WHERE `id` < 492597 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.003390s ]
  14. SELECT * FROM `article` WHERE `id` < 492597 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001598s ]
  15. SELECT * FROM `article` WHERE `id` < 492597 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.081551s ]
0.286568s