tivie/command

一个用于协调操作系统差异并安全执行外部程序的实用库

0.2.2 2014-12-24 05:05 UTC

This package is not auto-updated.

Last update: 2024-09-14 16:18:54 UTC


README

Build Status Latest Stable Version License

一个跨平台的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(); 

这将

  1. 运行$cmd1
  2. 如果$cmd1成功,则运行$cmd2
  3. 如果$cmd1$cmd2失败,则运行$cmd3
  4. 最后将运行$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

贡献者

Tivie Sophie-OS

许可

Command库在Apache 2.0许可下发布。更多信息,请参阅此存储库中的LICENSE文件或https://apache.ac.cn/licenses/LICENSE-2.0.txt