业务中,需要获取上传视频的时长,用于外部展示。
目前暂未找到理想的方法,只能用“大炮打蚊子”的方式——使用 ffmpeg。
通过下载 ffmpeg,在 BT 面板中安装 PHP 5.6,并放开 exec 函数。在建立的新站点中,使用 PHP5.6 版本。因为,为了安全 PHP 5.6 允许执行外部程序,且其他站点不使用 PHP 5.6 版本,而后,由 PHP 程序执行 ffmpeg,获取时间时长并存储到数据库中。
1、下载 ffmpeg
打开 https://www.gyan.dev/ffmpeg/builds/
点击左侧导航菜单中的 release builds,在右侧,找到,ffmpeg-release-essentials.zip ,点击以下载。
根据需要下载工具,点击左侧导航菜单中的 tools,在右侧,找到,ffmpeg-tools.zip ,点击以下载。
包含的工具有:
aviocat crypto_bench cws2fws ffescape ffeval ffhash fourcc2pixfmt graph2dot ismindex pktdumper probetest qt-faststart seek_print sidxindex venc_data_dump zmqsend
将压缩包中的 bin 目录解压,如存放在 d:\ffmpeg\bin 中。
2、设置环境变量
在“此电脑”中,点击右键,选择“属性”,之后选择“高级系统设置”。
在“高级选择卡”中点击“环境变量”,在“系统变量”中,找到“Path”,双击编辑后,添加新的环境变量值,如 d:\ffmpeg\bin。
3、新建建站
绑定的域名,填写,127.0.0.2(只用于内部访问), 无数据库,无 FTP,PHP 版本设置为 5.6,且在禁用函数中,移除 exec。
编辑 .user.ini,增加 TP5 站点目录,ffmpeg 程序目录。
open_basedir="d:/wwwroot/syncvideoinfo/;D:/wwwroot/kaoshi/;D:/ffmpeg/bin/;C:/Windows/Temp/;C:/Temp/;D:/BtSoft/temp/session/"
4、使用 SyncVideo.php
该程序是基于 TP5 框架的,因为需要设置 .env 所在目录,及解析视频地址。
之后读取数据库中存储的视频地址,并获取时间,然后,写入到数据库中。
<?php /** * 同步视频长度 */ class SyncVideo { /** @var string 锁文件路径 */ private $lockFile; /** @var string env 配置文件路径 */ private $dbEnvFile; /** @var string env 待解析视频目录 */ private $parseVideoDir; function __construct() { $this->lockFile = "./sync.lock"; $this->dbEnvFile = "../kaoshi/.env"; $this->parseVideoDir = "../kaoshi/public"; } public function canSync($write = false, $val = 0) { if ($write) { return file_put_contents($this->lockFile, $val) ? true : false; } $data = file_get_contents($this->lockFile); if ($data) { return false; } else { return true; } } public function getVideoMins($file) { $command = "ffmpeg -i " . $file . " 2>&1"; exec($command, $output); // 从输出中提取视频信息 $line = implode('', $output); // 提取视频时长 if (preg_match("/Duration: (.*?), /", $line, $matches)) { $time = explode(':', $matches[1]); return (intval($time[0]) * 60 * 60) + intval($time[1]) * 60 + intval($time[2]); } return 0; } /** * @throws Exception */ public function sync() { $res = [ 'count' => 0, 'list' => [], ]; if (!$this->canSync()) { throw new Exception("Please hold on ..."); } $this->canSync(true, date('Y-m-d H:i:s')); $dbConfig = parse_ini_file($this->dbEnvFile, true); try { // 创建连接 $conn = new PDO("mysql:host={$dbConfig['database']['hostname']};dbname={$dbConfig['database']['database']}", $dbConfig['database']['username'], $dbConfig['database']['password']); // 设置 PDO 错误模式为异常 $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $list = $conn->query("SELECT id,moive_file FROM fa_exam_course_movie where mins=0"); $res['count'] = count($list->rowCount() > 0 ? $list : []); foreach ($list as $row) { $t = time(); $sec = $this->getVideoMins($this->parseVideoDir . $row['moive_file']); // SQL 更新语句 $sql = "update fa_exam_course_movie set mins=:sec,updatetime=:t where id=:id"; // 预处理 SQL 语句 $stmt = $conn->prepare($sql); // 绑定参数 $stmt->bindParam(':sec', $sec); $stmt->bindParam(':t', $t); $stmt->bindParam(':id', $row['id']); // 执行更新操作 $stmt->execute(); $res['list'][] = [ 'id' => $row['id'], 'moive_file' => $row['moive_file'], 'length' => $sec, 'status' => $stmt->rowCount(), ]; } } catch (PDOException $e) { throw new Exception($e->getMessage()); } // 关闭连接 $conn = null; $this->canSync(true, 0); return $res; } } try { $data = (new SyncVideo())->sync(); echo date('Y-m-d H:i:s'), " count: ", $data['count'], PHP_EOL; foreach ($data['list'] as $v) { echo $v['id'], "\t", $v['moive_file'], "\t", $v['length'], "\t", $v['status'], PHP_EOL; } } catch (Exception $e) { echo $e; } // 程序正常退出 exit(0);
5、增加计划任务
任务类型为,访问 URL,每1分钟访问一次,地址为 http://127.0.0.2/SyncVideo.php。
这样就可以了,虽然不是最优方法,先实现再说,时间紧张。