一、php执行shell不阻塞方法
大家都知道php执行系统命令的方法有:
system() 输出并返回最后一行shell结果。
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。
这些方法都会等待命令执行完毕后才会继续执行后续的程序
不阻塞可以将命令输出的内容写入系统的一个回收站文件,这样程序就不会阻塞
例如:
shell_exec("/use/local/php/bin/php /www/t.php > /dev/null 2>&1 &");
shell中可能经常能看到:>/dev/null 2>&1
命令的结果可以通过%>的形式来定义输出
/dev/null 代表空设备文件
代表重定向到哪里,例如:echo “123” > /home/123.txt
1 表示stdout标准输出,系统默认值是1,所以”>/dev/null”等同于”1>/dev/null”
2 表示stderr标准错误
& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
那么本文标题的语句:
1>/dev/null 首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。
2>&1 接着,标准错误输出重定向等同于 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
二、PHP 使用 ffmpeg 获取视频缩略图
①、功能需求
上传好视频后,PHP 后台自动选取视频流中的某一帧作为视频封面。
②、工具:FFmpeg
FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序,功能很强大。
③、使用 ffmpeg
A、调用系统命令
在php文件中调用 system() 或 exec() 方法来实现帧图像的提取。(注意:在php中路径字符串中‘\’需转义:“\\”)
调用系统命令前请查看 php.ini 中的配置
disable_functions = passthru,chroot,chgrp,chown,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru
去掉你需要调用的系统命令,然后重启php,记住是重启 php
$name = rand(0, 9999999).".png";
$from = "F:\\test.mp4";
$to = "F:\\";
$str = "ffmpeg -i ".$from." -y -f mjpeg -ss 3 -t 1 -s 740x500 ".$to.$name;
system($str);
B、安装 PHP-FFMpeg
通过 composer 安装 PHP-FFMpeg
composer require php-ffmpeg/php-ffmpeg
或者直接下载 vendor
代码
require "vendor/autoload.php";
$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open("test.mp4");
$frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10));
$res = $frame->save("image.jpg");
三、Executable not found, proposed : avprobe, ffprobe
php-fpm 在执行 FFMPEG 的时候,没有找到 ffprobe 和 ffmpeg 解决办法如下:
命令行解决
通过 shell 确定文件位置
whereis ffprobe
/usr/local/bin/ffprobe
which ffmpeg
/usr/local/bin/ffmpeg
在初始化 FFMpeg 的时候将文件位置写入
$ffmpeg = FFMpeg::create([
'ffmpeg.binaries' => '/usr/local/bin/ffmpeg',
'ffprobe.binaries' => '/usr/local/bin/ffprobe',
]);
PHP 代码直接解决
// 写入 WWW 用户的环境变量
putenv('PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:$PATH');
// 通过 exec 函数找到文件对应位置
$ffmpeg = FFMpeg::create([
'ffmpeg.binaries' => exec('which ffmpeg'),
'ffprobe.binaries' => exec('which ffprobe'),
]);
虽然看似两种办法,其实解决思路是一致的,都是要指定 ffmpeg 和 ffprobe 文件的位置。理论上直接在服务器上将 www 用户的环境变量加入 ffmpeg 和 ffprobe 也可以解决此问题(没有测试,不保证有效,有兴趣的可以自行验证)。