分类 默认分类 下的文章

原文链接:https://juejin.cn/post/6950828432196386829

CLI 与 CGI
首先来看一下 CLI 和 CGI 的区别。我们都知道,Nginx 使用的是 FastCgi 来调用 PHP 的服务。 CGI 是通用编程接口,也就是给调用者提供的一种使用本程序的接口。 Nginx 这种类型的服务器并不是直接运行 PHP 程序的,而是通过 FastCgi 来执行 PHP 程序并获得返回结果。

CLI 则是 Command Line Interface,即命令行接口。主要用作 PHP 的开发外壳应用。也就是用 PHP 来进行 shell 脚本的开发。相比 linux 原生的 shell 来说,当然是方便了许多。在命令行状态下,直接使用 php 命令就可以运行某段 PHP 代码或某个 PHP 文件了。

另外,我们在命令行也可以直接使用 phpcgi 来运行一段 PHP 代码或者某个 PHP 文件,它和直接使用 php 命令来运行有什么区别呢?

  • CLI 的输出没有任何头信息
  • CLI 在运行时,不会把工作目录改为脚本的当前目录
  • CLI 出错时输出纯文本的错误信息(非 HTML 格式)
    强制覆盖了 php.ini 中的某些设置,因为这些设置在外壳环境下是没有意义的

    
    // PHP的CLI命令行运行模式浅析.php
    echo getcwd();
    

    我们选取最典型的一个例子,我们运行的这个文件中,使用 getcwd() 输出当前脚本运行的目录,可以看出两种运行方式输出的结果明显不同。php-cgi 是以文件所在目录为基准输出,而 php 则是以当前运行这个命令的目录为基准输出。

直接运行 PHP 代码
在做一些简单的调试的时候,我们可以直接通过 CLI 来运行一段代码。

// php -r "echo 121;"
// 121

也就是简单的加个 -r 参数,后面跟上一段代码,这段代码必须用引号括起来。而且这个引号更推荐使用单引号,后面的例子会展示为什么用单引号更好。

CLI 获取参数
命令行模式下也是可以给脚本传递参数的。


// PHP的CLI命令行运行模式浅析.php
print_r($argv);
// php-cgi dev-blog/php/202004/source/PHP的CLI命令行运行模式浅析.php 1 2 3
// X-Powered-By: PHP/7.3.0
// Content-type: text/html; charset=UTF-8

// php dev-blog/php/202004/source/PHP的CLI命令行运行模式浅析.php 1 2 3
// Array
// (
//     [0] => dev-blog/php/202004/source/PHP的CLI命令行运行模式浅析.php
//     [1] => 1
//     [2] => 2
//     [3] => 3
// )

在测试文件中,我们打印了 argv变量。PHP脚本运行的时候,会将命令行的所有参数保存在argv变量。PHP脚本运行的时候,会将命令行的所有参数保存在argv 变量中,并且还有一个 $argc 变量会保存参数的个数。

我们依然是使用 php-cgi 和 php ,两种模式来测试,从这里我们能发现 php-cgi 模式中 $argv 打印的内容竟然是头信息,而不是具体的参数信息。这也没错,毕竟 CGI 模式本来就是为 Web 服务器提供的接口,所以它接收的是 post 、 get 这类的参数而不是命令行的参数。

CLI 模式下我们正常获得了参数内容,并且 $argv[0] 始终保存的是当前运行文件及路径。

CLI 命令行实用选项
最后,我们再介绍一些命令行中常用的选项。
-r 直接运行代码时的参数传递


// php -r "var_dump($argv);" app 
// Warning: var_dump() expects at least 1 parameter, 0 given in Command line code on line 1
// 双引号 ",sh/bash 实行了参数替换

// php -r 'var_dump($argv);' app
// array(2) {
//     [0]=>string(19) "Standard input code"
//     [1]=>string(3) "app"
// }

// php -r 'var_dump($argv);' -- -h
// array(2) {
//     [0]=>string(19) "Standard input code"
//     [1]=>string(2) "-h"
// }

第一段代码在对双引号运行的 CLI 代码进行参数传递的时候,会直接报警告。其实很好理解,双引号里面的$会让系统的 sh/bash 以为这是个变量从而进行变量参数替换。所以更推荐使用单引号进行日常的简单测试。

第二段代码能够正常打印传递进来的参数内容。第三行代码则是需要传递带 - 符号的内容时,需要先给一个 -- 参数列表分隔符。这是因为 -xxx 的内容会让 php 命令认为这是一个命令选项而不是参数,所以我们添加一个分隔符就可以让分隔符之后的参数内容原样传递进代码中。

交互式地运行 PHP


// php -a
// php > $a = 1;
// php > echo $a;
// php > 1

添加一个 -a 选项,PHP 就会以交互式地形式运行,我们可以直接在交互状态下写代码或运行任何内容。

查看 phpinfo() 及已经安装的模块
这两个应该是大家经常会使用的两个选项。

// 输出 phpinfo()
// php -i

// 输出 PHP 中加载的模块
// php -m

// 查看模块详细信息
// php --ri swoole 

另外我们还可以通过 --ri 模块名 这个命令来查看具体某个扩展模块的详细信息。比如这里我们可以查看到 swoole 扩展的版本及相关的配置信息。

查看某个文件


// 显示去除了注释和多余空白的源代码
// php -w dev-blog/php/202004/source/PHP的CLI命令行运行模式浅析.php
// <?php
//  echo getcwd(); print_r($argv);

// 通过 linux 管道读取输入
// cat dev-blog/php/202004/source/PHP的CLI命令行运行模式浅析.php | php -r "print file_get_contents('php://stdin');"
// ......这个文件里面所有的内容

最后两个小技巧,一个是通过 -w 选项,我们可以打印这个 php 文件中所有非注释和换行的内容。可以看成是像前端的代码压缩一样的能力。我们这个测试文件中有非常多的注释,通过这个命令后我们打印出来的内容是去除掉所有注释和空白行的结果。

另一个是我们可以用 linux 管道的方式向 PHP CLI 发送数据。这里我们通过 cat 查看我们的测试文件然后通过管道发送给 PHP CLI,在脚本中使用 STDIN 来读取管道发送过来的内容完成了整个文件内容的打印。这里我们没进行任何过滤,所以打印的是整个文件里面的内容,大家可以运行这个命令来测试。

总结
其实命令行模式运行的时候还有很多的选项,这里我们只是选取了一部分非常有用的内容进行展示。当然,大部分框架都提供了用于命令行的脚本框架,比如 laravel 中可以通过 php artisan make:command 来创建命令行脚本,然后使用 php artisan 来运行框架中的脚本。这些内容将来我们在学习框架方面知识的内容将会进行详细的讲解。

命令行 CLI 模式的应用非常广泛,几乎任何项目中都会使用到,所以,深入的学习掌握它将会使我们大受裨益。

官方网站:
https://vueuse.org/

VueUse是一个基于Composition API的实用函数集合,它的功能丰富有200+功能,无缝迁移适用于Vue3和Vue2.7版本之后 同时支持tree shaking,中文文档由itxst翻译,并匹配了对应的demo例子,从VueUse 4.0版本开始,通过vue-demi实现了一个包同时支持 Vue 2 和 Vue 3 。
中文教程:
https://www.itxst.com/vueuse/tutorial.html

VueUse是一个包含众多实用工具方法和Hooks的Vue.js库,如useMouse、useKeyboard等,帮助开发者避免重复逻辑,实现鼠标追踪、键盘监听等交互功能,提高开发效率和应用性能。

技术博客文章原文:
https://blog.csdn.net/weixin_46254812/article/details/130651068

更全的:https://juejin.cn/post/7089275800913969159

制表符:

─ ━│┃╌╍╎╏┄ ┅┆┇┈ ┉┊┋┌┍┎┏┐┑┒┓└ ┕┖┗ ┘┙┚┛├┝┞┟┠┡┢┣ ┤┥┦┧┨┩┪┫┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╪ ╫ ╬═║╒╓╔ ╕╖╗╘╙╚ ╛╜╝╞╟╠ ╡╢╣╤ ╥ ╦ ╧ ╨ ╩ ╳╔ ╗╝╚ ╬ ═ ╓ ╩ ┠ ┨┯ ┷┏ ┓┗ ┛┳ ⊥ ﹃ ﹄┌ ╮ ╭ ╯╰

RDB(Redis Database)是 Redis 提供的一种持久化策略,它通过将 Redis 在某个时间点上的数据集快照写入磁盘来实现持久化。RDB 持久化策略的核心思想是定期生成数据快照,并将其保存到磁盘文件中。以下是 RDB 持久化策略的详细说明:

RDB 持久化的优点

1.高效性:

RDB 文件是经过压缩的二进制文件,占用磁盘空间小,适合备份和恢复。
恢复数据时,RDB 文件的加载速度通常比 AOF 快。
2.适合备份:

RDB 文件可以方便地用于数据迁移或灾难恢复。
3.对性能影响较小:

RDB 持久化是通过 fork 子进程来完成的,主进程不需要参与 I/O 操作,因此对 Redis 的性能影响较小。

RDB 持久化的缺点

1.数据可能丢失:

RDB 是定期生成快照,如果 Redis 在两次快照之间崩溃,可能会丢失最后一次快照之后的数据。
2.不适合实时性要求高的场景:

由于 RDB 是定时快照,无法做到实时持久化,因此不适合对数据完整性要求极高的场景。

RDB 持久化的配置

RDB 持久化的配置主要通过 Redis 配置文件(redis.conf)中的以下参数进行控制:

1.save:

定义触发 RDB 快照的条件。例如:

save 900 1      # 900 秒内至少有 1 个 key 被修改,则触发快照
save 300 10     # 300 秒内至少有 10 个 key 被修改,则触发快照
save 60 10000   # 60 秒内至少有 10000 个 key 被修改,则触发快照

可以配置多个 save 规则,满足任意一个条件就会触发快照。
2.dbfilename:

指定 RDB 文件的名称,默认为 dump.rdb。
3.dir:

指定 RDB 文件的保存路径,默认为 Redis 的工作目录。
4.stop-writes-on-oome:

当 Redis 内存不足时,是否停止写操作以生成 RDB 文件。默认值为 yes
5.rdbcompression:

是否对 RDB 文件进行压缩,默认值为 yes。
6.rdbchecksum:

是否对 RDB 文件进行校验,默认值为 yes。

RDB 持久化的工作流程

1.Redis 主进程检查是否满足 save 条件。
2.如果满足条件,Redis 主进程会 fork 一个子进程。
3.子进程负责将内存中的数据写入 RDB 文件。
4.子进程完成写操作后,主进程替换旧的 RDB 文件。
5.子进程退出,主进程继续处理客户端请求。

RDB 持久化的触发方式

1.自动触发:

根据 save 配置规则自动触发快照。
2.手动触发:

使用 SAVE 命令:阻塞主进程,直到快照完成。
使用 BGSAVE 命令:异步触发快照,主进程可以继续处理客户端请求。

RDB 持久化的适用场景

数据备份和恢复。
对数据完整性要求不高,但需要快速恢复数据的场景。
数据集较大,且写操作频率较低的场景。
RDB 与 AOF 的对比
特性 RDB AOF
持久化方式 快照 日志追加
文件大小 较小 较大
恢复速度 快 慢
数据完整性 可能丢失部分数据 更完整,最多丢失 1 秒数据
对性能影响 较小 较大
适用场景 备份、快速恢复 数据完整性要求高

AOF(Append Only File)持久化机制详解

1. AOF 的核心原理
AOF 通过记录 Redis 执行的所有写操作命令(如 SET、DEL 等)来持久化数据,而非直接保存数据快照。Redis 重启时,会重新执行 AOF 文件中的命令以恢复数据。

记录内容:仅记录写操作命令,不记录读操作。
追加模式:以文本形式追加到文件末尾,支持实时同步。
2. AOF 的工作流程
1.命令追加:写命令被追加到 AOF 缓冲区。
2.文件同步:根据 appendfsync 参数配置,将缓冲区内容同步到磁盘:

  • always:每次写入后立即同步(数据最安全,性能最差)。
  • everysec(默认):每秒同步一次(平衡性能与安全性)。
  • no:由操作系统决定同步时机(性能最佳,数据风险最高)。

3.文件重写:AOF 文件过大时,Redis 会生成新的 AOF 文件,仅保留最小命令集以压缩体积。
4.数据恢复:重启时加载 AOF 文件并逐条执行命令。
3. AOF 的优缺点
优点 缺点
高数据安全性:最多丢失 1 秒数据(everysec)或单条命令(always)。 文件体积大:记录所有命令,长期积累可能导致文件过大。
可恢复性强:支持手动修复损坏的 AOF 文件(如使用 redis-check-aof)。 恢复速度慢:需逐条执行命令,数据量大时耗时较长。
实时性高:写操作实时记录,适合对数据完整性要求高的场景。 磁盘 I/O 压力大:频繁写入可能影响性能。
4. AOF 的配置与优化
启用 AOF:在 redis.conf 中设置 appendonly yes。
同步策略:通过 appendfsync 调整同步频率(推荐 everysec)。
自动重写:通过 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 控制重写条件(如文件增长 100% 且超过 64MB 时触发)。
混合持久化:结合 RDB 快照与 AOF 日志,提升恢复速度与数据安全性(需 Redis 4.0+)。

总结
RDB 持久化是一种高效且适合备份的持久化策略,但在数据完整性和实时性方面存在一定局限性。在实际应用中,可以根据需求选择 RDB、AOF 或两者结合使用,以达到最佳的性能和数据安全性。

按文件大小拆分

./split-video.sh huge-video.mov 64000000 "-c:v libx264 -crf 23 -c:a copy -vf scale=960:-1"

split-video.sh 脚本内容:

#!/bin/bash
# Short script to split videos by filesize using ffmpeg by LukeLR

if [ $# -ne 3 ]; then
    echo 'Illegal number of parameters. Needs 3 parameters:'
    echo 'Usage:'
    echo './split-video.sh FILE SIZELIMIT "FFMPEG_ARGS'
    echo 
    echo 'Parameters:'
    echo '    - FILE:        Name of the video file to split'
    echo '    - SIZELIMIT:   Maximum file size of each part (in bytes)'
    echo '    - FFMPEG_ARGS: Additional arguments to pass to each ffmpeg-call'
    echo '                   (video format and quality options etc.)'
    exit 1
fi

FILE="$1"
SIZELIMIT="$2"
FFMPEG_ARGS="$3"

# Duration of the source video
DURATION=$(ffprobe -i "$FILE" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)

# Duration that has been encoded so far
CUR_DURATION=0

# Filename of the source video (without extension)
BASENAME="${FILE%.*}"

# Extension for the video parts
#EXTENSION="${FILE##*.}"
EXTENSION="mp4"

# Number of the current video part
i=1

# Filename of the next video part
NEXTFILENAME="$BASENAME-$i.$EXTENSION"

echo "Duration of source video: $DURATION"

# Until the duration of all partial videos has reached the duration of the source video
while [[ $CUR_DURATION -lt $DURATION ]]; do
    # Encode next part
    echo ffmpeg -i "$FILE" -ss "$CUR_DURATION" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
    ffmpeg -ss "$CUR_DURATION" -i "$FILE" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"

    # Duration of the new part
    NEW_DURATION=$(ffprobe -i "$NEXTFILENAME" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)

    # Total duration encoded so far
    CUR_DURATION=$((CUR_DURATION + NEW_DURATION))

    i=$((i + 1))

    echo "Duration of $NEXTFILENAME: $NEW_DURATION"
    echo "Part No. $i starts at $CUR_DURATION"

    NEXTFILENAME="$BASENAME-$i.$EXTENSION"
done

按时长拆分

ffmpeg -i "input_video.MTS" -ss 164 -f segment -segment_time 120 -vcodec copy -c:a copy -reset_timestamps 1 output_video%d.MTS
#! /bin/bash
#use: ./split.sh ./Captures/di_er_shi_tiao.mp4 0 60 ./diershitiao/video_

ffmpeg -i $1 -ss $2 -f segment -segment_time $3 -vcodec copy -c:a copy -reset_timestamps 1 ${4}%d.mp4

按场景分镜拆分:
python库安装

pip install --upgrade scenedetect[opencv]

window批处理命令: split.bat

scenedetect --input %1 --output %2 detect-content split-video

#用法
split.bat  xx.mp4 your_out_dir_xxx