edrisa/command

PHP的外部命令运行器/执行器

dev-master 2022-10-04 13:28 UTC

This package is auto-updated.

Last update: 2024-09-04 17:15:42 UTC


README

Build Status

PHP的外部命令运行器/执行器。这是一个面向对象的、健壮的execshell_exec、反引号操作符等的替代品。

由于PHP中proc_open()支持不完整,此包在Windows上无法可靠地运行。

此包受http://pollinimini.net/blog/php-command-runner/的启发。

运行命令

在最简单的形式中,您可以像这样执行命令

$cmd = Command::factory('ls')->run();

添加参数和选项

在这里我们安全地添加参数

use Edrisa\Command\Command;

$cmd = Command::factory('/usr/bin/svn')
    ->option('--username', 'drslump')
    ->option('-r', 'HEAD')
    ->option('log')
    ->argument('http://code.google.com/drslump/trunk')
    ->run();

echo $cmd->getStdOut();

使用回调进行增量更新

通常,所有命令输出都会被缓冲,一旦命令完成,您就可以访问它。通过使用回调,输出会被缓冲,直到接收到的字节数达到期望的数量(请参阅Command::setReadBuffer(int $bytes)),然后传递给您的回调函数

use Edrisa\Command\Command;

$cmd = Command::factory('ls')
    ->setCallback(function($pipe, $data) {
        // Gets run for every 4096 bytes
        echo $data;
    })
    ->setReadBuffer(4096)
    ->setDirectory('/tmp')
    ->option('-l')
    ->run();

或者,您可以将Command::run(string $stdin, bool $lines)的第二个参数设置为true,以便每次输出一行时执行一次回调

use Edrisa\Command\Command;

$cmd = Command::factory('ls')
    ->setCallback(function($pipe, $data){
        // Gets run for each line of output
        echo $data;
    })
    ->setDirectory('/tmp')
    ->option('-l')
    ->run(null, true);

流式传输大型命令输出

默认情况下,STDOUT和STDERR被PHP内部收集。如果您有大量数据要传递给命令,您应该流式传输它(请参阅下文的STDIN来自流)。如果您有大量来自命令的输出,您应该使用回调流式传输它

use Edrisa\Command\Command;

require_once __DIR__.'/../vendor/autoload.php';

$filename = __DIR__.'/../README.md';
$stdin = fopen($filename, 'r');

// This will read README.md and grep for lines containing 'the'
$cmd = Command::factory("grep 'the'")
    ->setCallback(function($pipe, $data) {
        // Change the text to uppercase
        $data = strtoupper($data);

        if ($pipe === Command::STDERR) {
            Command::echoStdErr($data);
        } else {
            echo $data;
        }
    })
    ->run($stdin);

fclose($stdin);

无转义运行命令

默认情况下,传递给Command::factory(string $command, bool $escape)的命令将被转义,因此像|>这样的字符将被分别替换为\|\>。为了防止命令工厂转义您的命令,您可以传递第二个参数为true

use Edrisa\Command\Command;

$cmd = Command::factory('grep CRON < /var/log/syslog | head', true)->run();

echo $cmd->getStdOut();

输出到STDERR

要将内容输出到STDERR,有一个辅助函数Command::echoStdErr(string $content)

use Edrisa\Command\Command;

$cmd = Command::factory('grep CRON < /var/log/syslog | head', true)
    ->setCallback(function($pipe,$data) {
        if ($pipe === Command::STDERR) {
            Command::echoStdErr($data);
        } else {
            echo $data;
        }
    })
    ->run();

使用STDIN

您可以使用字符串或流资源(如文件句柄)提供STDIN的数据

STDIN来自字符串

use Edrisa\Command\Command;

$stdin = "banana
orange
apple
pear
";

$cmd = Command::factory("sort")
    ->run($stdin);

echo $cmd->getStdOut();

STDIN来自流

use Edrisa\Command\Command;

$filename = __DIR__.'/../README.md';
$stdin = fopen($filename, 'r');

// This will count the number of words in the README.md file
$cmd = Command::factory("wc")
    ->option("--words")
    ->run($stdin);

fclose($stdin);

$words = trim($cmd->getStdOut());
echo "File $filename contains $words words\n";

您的系统的STDIN也是一个流,因此您可以接受来自命令行或管道到您的脚本的输入

use Edrisa\Command\Command;

echo "Type some words, one per line, then press CTRL-D and they will be sorted:\n";

$cmd = Command::factory("sort")
    // This causes Command to use the real STDIN
    ->run(STDIN);

echo "\n";
echo $cmd->getStdOut();

一些其他功能

  • StdIn数据可以作为run()的参数提供给进程
  • 使用setEnv()为进程设置环境变量
  • option()的第二个参数和argument()的参数将自动转义。
  • 选项分隔符默认为空白字符,可以通过手动将第三参数设置为option()或使用setOptionSeparator()设置新的默认值来更改。
  • 为了方便起见,将proc_open包装器公开为静态方法Command::exec()