tivie / command
一个用于协调操作系统差异并安全执行外部程序的实用库
Requires
- php: >=5.3.0
- tivie/php-os-detector: 1.0.*
Requires (Dev)
- phpunit/phpunit: 4.3.*
This package is not auto-updated.
Last update: 2024-09-14 16:18:54 UTC
README
一个跨平台的PHP实用库,用于协调操作系统差异并以更安全的方式执行外部程序
简介
Command是一个小巧轻量级的实用库,使您能够以更安全的方式运行外部程序或命令。它还协调了Windows和Unix环境之间的差异,消除了为每个平台创建特定代码的需要。
特性
- 平台无关:在Unix和Windows上运行相同的代码
- 修复Windows环境中
proc_open
的问题 - 面向对象的命令构建器,具有流畅的接口
- 参数转义,用于更安全的命令调用
- 在Windows和Unix环境中支持条件调用和管道的命令链
安装
您可以通过克隆git仓库或使用composer来安装它。
Git克隆
git clone https://github.com/tivie/command.git
Composer
将这些行添加到您的composer.json中
{ "require": { "tivie/command": "*" } }
或者运行以下命令
php composer.phar require tivie/command
快速使用指南
简单示例
假设我们想ping google.com 3次,每次32字节的分组。使用PHP,我们可以这样做
exec("ping -c 3 -s 24 www.google.com", $otp, $ec);
然而,我们希望使我们的命令更加安全,并转义我们的参数。
$host = 'www.google.com'; $c = 3; $s = 24; //Linux adds 8 bytes of ICMP header data $cmd = sprintf("ping -c %d -s %d %s", escapeshellarg($c), escapeshellarg($s), escapeshellarg($host)); exec($cmd, $otp, $ec);
这在GNU/Linux环境中应该按预期工作,但在Windows上会失败,因为'-c'是一个未识别的标志,而'-s'意味着完全不同的事情。Windows版本将是
$host = 'www.google.com'; $c = 3; $s = 32; $cmd = sprintf("ping -n %d -l %d %s", escapeshellarg($c), escapeshellarg($s), escapeshellarg($host)); exec($cmd, $otp, $ec);
如果我们想确保跨平台兼容性,我们需要进行某种类型的操作系统检查,并根据该检查运行相应的命令
$host = 'www.google.com'; $c = 3; if (PHP_OS === 'WINDOWS' || PHP_OS === 'WIN32' || PHP_OS === 'WINNT' /* And a few more*/ ) { $s = 32; $cmd = sprintf("ping -n %d -l %d %s", escapeshellarg($c), escapeshellarg($s), escapeshellarg($host)); } else { $s = 24; //Linux adds 8 bytes of ICMP header data $cmd = sprintf("ping -c %d -s %d %s", escapeshellarg($c), escapeshellarg($s), escapeshellarg($host)); } exec($cmd, $otp, $ec);
虽然这在大多数情况下都有效,但在更复杂的命令(或命令链)中,您将被迫重复很多次,进行很多条件检查。
使用命令库,您不需要这样做:它会为您完成这项工作。
$cmd = new \Tivie\Command\Command(\Tivie\Command\ESCAPE); $cmd->setCommand('ping') ->addArgument( new Argument('-n', 3, \Tivie\OS\WINDOWS_FAMILY) ) ->addArgument( new Argument('-l', 32, \Tivie\OS\WINDOWS_FAMILY) ) ->addArgument( new Argument('-c', 3, \Tivie\OS\UNIX_FAMILY) ) ->addArgument( new Argument('-s', 24, \Tivie\OS\UNIX_FAMILY) ) ->addArgument( new Argument('www.google.com') ); $result = $cmd->run();
Command::run()
返回一个结果对象,您可以通过它来检索命令的结果。
echo $result->getStdOut(); // The Standard Output of the command echo $result->getLastLine(); // The last line of the Standard Output echo $result->getStdIn(); // The passed standard input echo $result->getStdErr(); // The standard error echo $result->getExitCode(); // The command's exit code
链式命令
命令库支持链式命令
$cmd1 = new \Tivie\Command\Command(); $cmd1->setCommand('php') ->addArgument(new Argument('-v')); $cmd2 = new \Tivie\Command\Command(); $cmd2->setCommand('echo') ->addArgument(new Argument('foo')); $results = $cmd1->chain() ->add($cmd2) /* any number of commands here */ ->run();
$results
将是一个包含结果对象的数组。
您还可以指定链式条件,类似于Linux的链式运算符。
RUN_REGARDLESS (';')
$cmd1->chain()->add($cmd2, \Tivie\Command\RUN_REGARDLESS)->run();
$cmd2
将无论$cmd1
的退出代码如何都运行。模仿';'链式运算符,是默认操作。
RUN_IF_PREVIOUS_SUCCEEDS ('&&')
$cmd1->chain()->add($cmd2, \Tivie\Command\RUN_IF_PREVIOUS_SUCCEEDS)->run();
$cmd2
只有在$cmd1
成功时才会运行,即,如果它以退出代码0退出。模仿 '&&' 链式运算符。
RUN_IF_PREVIOUS_FAILS ('||')
$cmd1->chain()->add($cmd2, \Tivie\Command\RUN_IF_PREVIOUS_FAILS)->run();
$cmd2
只有在$cmd1
失败时才会运行,即,如果它以不同于0的退出代码退出。模仿 '||' 链式运算符。
复杂命令链
尽管如此,您可以创建复杂的命令链。例如
$cmd1->chain() ->add($cmd2, \Tivie\Command\RUN_IF_PREVIOUS_SUCCEEDS) ->add($cmd3, \Tivie\Command\RUN_IF_PREVIOUS_FAILS) ->add($cmd4, \Tivie\Command\RUN_REGARDLESS) ->run();
这将
- 运行
$cmd1
- 如果
$cmd1
成功,则运行$cmd2
- 如果
$cmd1
或$cmd2
失败,则运行$cmd3
- 最后将运行
$cmd4
管道
命令库支持两种类型的管道
- STDOUT->STDIN
- STDOUT->Argument
STDOUT到STDIN
将一个命令的标准输出连接到下一个命令的标准输入非常简单。你只需将Chain::add()
的第三个参数设置为true
。
$cmd1->chain()->add($cmd2, \Tivie\Command\RUN_REGARDLESS, true)
STDOUT到参数
你也可以将前一个命令的STDOUT作为下一个命令的参数。库会在命令的参数键和值中查找特殊的关键字(占位符)‘!PIPE!’,并将其替换为前一个命令的STDOUT。然后你需要在Chain::add()
函数中将第三个参数传递为true,与上面的情况相同。
$cmd2->addArgument(new Argument('foo'), \Tivie\Command\PIPE_PH); // PIPE_PH = '!PIPE!' $cmd1->chain()->add($cmd2, \Tivie\Command\RUN_REGARDLESS, true);
添加对其他操作系统的支持
如果你需要进行更具体的操作系统检查,可以扩展Detector类或创建一个实现DetectorInterface的新类。更多信息,请参阅php-os-detector文档。
示例
const OS_2_WARP = 65540; //65536 + 4 class MyOSDetector extends \Tivie\OS\Detector { public function detect() { $os = parent::detect(); switch($os->name) { case "OS/2": case "OS/2 WARP": $os->family = \Tivie\Command\OS\OTHER_FAMILY; $os->def = OS_2_WARP; break; } return $os; } }
你不需要创建一个关于新操作系统的新的常量(你可以使用预存在的家族之一)。然而,如果你选择这样做,新的操作系统常量值应该是2^n序列中的唯一数字加上该操作系统所属的家族。在示例中,我们选择了第16项(65536)加上操作系统家族(在这种情况下,FAMILY_OTHER),它是4。
贡献
请随意通过分叉或提出建议来贡献。
问题跟踪器:https://github.com/tivie/command/issues
源代码:https://github.com/tivie/command
贡献者
许可
Command库在Apache 2.0许可下发布。更多信息,请参阅此存储库中的LICENSE文件或https://apache.ac.cn/licenses/LICENSE-2.0.txt。