gpt4 book ai didi

php - 使用 PHP 打开 PTY 的最佳方式

转载 作者:行者123 更新时间:2023-12-03 09:49:49 25 4
gpt4 key购买 nike

问题描述
我想用 PHP 打开一个 Linux 伪终端,但似乎没有简单的方法可以做到这一点。我尝试了不同的解决方案,但似乎都不够好。
PTY 的目标是模拟具有与 zsh 等程序完美交互的能力的终端。和 sudo .包括 Python 和 C 在内的其他编程语言都有相应的函数或库。 Python 有 PTY library可以简单地做pty.spawn("/bin/zsh") , C 有 openpty() 功能。
我理想的最终目标是拥有一个 PHP 函数,它允许我从 PTY 终端读取和写入,并且不需要安装外部库。 (许多共享主机提供商不允许这样做。)
到目前为止我尝试过的
使用 proc_open()
我最初的想法是使用 proc_open()使用 stdin 创建 Bash 终端的 PHP 函数, stdoutstderr管道(基于 PHP documentation 中的示例 #1) 然而,这很快就被证明是有问题的,因为它实际上不是真正的 PTY。运行stty -a错误 stty: stdin isn't a terminal .以下是复制此内容的说明。

  • 使用 php pty_test.php 运行它
  • 使用 cat /tmp/stdout 读取 shell 的输出.
  • 使用 > /tmp/stdin 输入命令.

  • 这是我用于此的 PHP 代码:
    <?php
    /* pty_test.php */


    ini_set('display_errors', 1);
    ini_set('display_startup_ūūerrors', 1);
    error_reporting(E_ALL);

    define("STD_IN", 0);
    define("STD_OUT", 1);
    define("STD_ERR", 2);

    set_time_limit(0);
    umask(0);

    $chunk_size = 1400;
    $write_a = null;
    $error_a = null;
    $shell = "/bin/sh -i ";
    $stdin_fifo = "/tmp/stdin";
    $stdout_fifo = "/tmp/stdout";

    posix_mkfifo($stdin_fifo, 0644);
    posix_mkfifo($stdout_fifo, 0644);
    $resource_stdin = fopen($stdin_fifo, "rb+");
    $resource_stdout = fopen($stdout_fifo, "wb+");

    $descriptorspec = array(
    STD_IN => array("pipe", "rb"),
    STD_OUT => array("pipe", "wb"),
    STD_ERR => array("pipe", "wb")
    );

    $process = proc_open($shell, $descriptorspec, $pipes, null, $env = null);

    stream_set_blocking($pipes[STD_IN], 0);
    stream_set_blocking($pipes[STD_OUT], 0);
    stream_set_blocking($pipes[STD_ERR], 0);
    stream_set_blocking($resource_stdin, 0);
    stream_set_blocking($resource_stdout, 0);

    while (1) {

    $read_a = array($resource_stdin, $pipes[STD_OUT], $pipes[STD_ERR]);
    $num_changed_streams = stream_select($read_a, $write_a, $error_a, null);

    if (in_array($resource_stdin, $read_a)) {
    $input = fread($resource_stdin, $chunk_size);
    fwrite($pipes[STD_IN], $input);
    }
    if (in_array($pipes[STD_OUT], $read_a)) {
    $input = fread($pipes[STD_OUT], $chunk_size);
    fwrite($resource_stdout, $input);
    }
    if (in_array($pipes[STD_ERR], $read_a)) {
    $input = fread($pipes[STD_ERR], $chunk_size);
    fwrite($resource_stdout, $input);
    }
    }

    fclose($resource_stdin);
    fclose($resource_stdout);
    fclose($pipes[STD_IN]);
    fclose($pipes[STD_OUT]);
    fclose($pipes[STD_ERR]);
    proc_close($process);
    unlink($stdin_fifo);
    unlink($stdout_fifo);

    ?>
    python PTY
    我注意到运行 python3 -c "import pty;pty.spawn('/bin/bash');"在非 pty shell(我在上面描述的)中将产生一个完全交互式的 PTY shell,如我所愿。这导致了一个半好的解决方案:设置 $shell变量为 python3 -c "import pty;pty.spawn('/bin/bash')"将使用 Python3 生成交互式 shell。但是依赖外部软件并不理想,因为并不总能保证拥有 Python3。 (而且这个解决方案也感觉太hacky了......)
    /dev/ptmx
    我正在阅读 source codeproc_open()函数还找到了 openpty() 的来源.不幸的是,PHP 不能直接调用这个函数,但也许可以复制它的行为。
    我可以 fopen("/dev/ptmx","r+")创建一个新的从站但是 openpty()也使用 grantpt()unlockpt() , 在 PHP 中不可用。
    外函数接口(interface)
    FFI允许访问外部库。也许可以导入 pty.h并运行 openpty() .不幸的是,FFI 是非常实验性的,可能并不总是可用。
    TL;博士
    使用 PHP 生成 PTY 的最安全和最可靠的方法是什么?

    最佳答案

    您不必使用 FFI 来编写 PHP 共享库。
    我只是尝试为此目的编写一个开源 PHP 库。我将它命名为 TeaOpenPTY。我认为这可以成为一个很好的例子,如何用 C 编写一个简单的 PHP 库。

  • GitHub 仓库:https://github.com/ammarfaizi2/TeaOpenPTY
  • 预编译共享库:https://github.com/ammarfaizi2/TeaOpenPTY/raw/master/compiled/tea_openpty.so

  • 如何使用 TeaOpenPTY 库?
    文件 test.php
    <?php

    use TeaOpenPTY\TeaOpenPTY;

    $app = "/usr/bin/bash";
    $argv = [$app, "-i"];

    $teaOpenPTY = new TeaOpenPTY($app);

    echo "Starting TeaOpenPTY...\n";

    $ret = $teaOpenPTY->exec(...$argv);

    if ($ret === -1) {
    echo "Error: ", $teaOpenPTY->error(), "\n";
    }

    echo "TeaOpenPTY terminated!\n";
    ammarfaizi2@integral:/tmp$ wget https://github.com/ammarfaizi2/TeaOpenPTY/raw/master/compiled/tea_openpty.so
    [...output abbreviated...]
    2020-12-28 14:39:20 (612 KB/s) - ‘tea_openpty.so’ saved [19048/19048]

    ammarfaizi2@integral:/tmp$ echo $$ # Show the current bash PID
    19068
    ammarfaizi2@integral:/tmp$ php -d extension=$(pwd)/tea_openpty.so test.php
    Starting TeaOpenPTY...
    ammarfaizi2@integral:/tmp$ echo $$ # Now we are in the terminal spawned by tea_openpty
    329423
    ammarfaizi2@integral:/tmp$ stty -a
    speed 38400 baud; rows 46; columns 192; line = 0;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
    eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
    werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
    -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
    -iuclc -ixany -imaxbel iutf8
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
    echoctl echoke -flusho -extproc
    ammarfaizi2@integral:/tmp$ exit # Terminate the terminal
    exit
    TeaOpenPTY terminated!
    ammarfaizi2@integral:/tmp$ echo $$
    19068
    ammarfaizi2@integral:/tmp$

    关于php - 使用 PHP 打开 PTY 的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65460864/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com