Build an Asynchronous Web SSH with Workerman, popen, and WebSocket

This guide shows how to use PHP's popen with Workerman 5.0 and a WebSocket worker to run command‑line tasks asynchronously, manage a process pool, and stream output to a web client, enabling a functional web‑based SSH interface.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
Build an Asynchronous Web SSH with Workerman, popen, and WebSocket

Origin

The idea came from a group discussion where a member asked how to execute command‑line tasks asynchronously with a notification mechanism for a web‑SSH project. The suggestion was to use popen for process creation.

Implementation

Using Workerman 5.0, a ProcessPool class was created to manage popen processes. The pool tracks active processes, limits the maximum number of concurrent processes, and provides methods to add, release, and count processes.

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

date_default_timezone_set('Asia/Shanghai');

class ProcessPool {
    private array $processes = [];
    public int $maxProcesses;

    public function __construct($maxProcesses = 5) {
        $this->maxProcesses = $maxProcesses;
    }

    public function add(string $command) {
        $process = popen($command, 'r');
        $this->processes[] = $process;
        return $process;
    }

    public function releaseProcess($process): void {
        $key = array_search($process, $this->processes);
        if ($key !== false) {
            unset($this->processes[$key]);
        }
    }

    public function processCount(): int {
        return count($this->processes);
    }
}

$task = new \Workerman\Worker('websocket://0.0.0.0:3232');
$processPool = new ProcessPool(5);

$task->onWorkerStart = function (\Workerman\Worker $worker) use ($processPool) {
    \Workerman\Timer::add(1, function () use ($processPool) {
        var_dump('[' . date('H:i:s') . '] 活动进程数:' . $processPool->processCount());
    });
};

$task->onMessage = function (\Workerman\Connection\TcpConnection $connection, $str) use ($processPool) {
    $data = json_decode($str, JSON_OBJECT_AS_ARRAY);
    $command = $data['command'] ?? '';
    if (empty($command)) {
        return $connection->send('无效命令');
    }
    if ($processPool->processCount() >= $processPool->maxProcesses) {
        return $connection->send('使用进程数已达最大数,等待中...');
    }
    $process = $processPool->add($command);
    if (is_resource($process)) {
        \Workerman\Worker::$globalEvent->onReadable($process, function ($pipe) use ($connection, $process, $processPool) {
            $output = fread($pipe, 8192);
            if ($output === false || feof($pipe)) {
                fclose($pipe);
                $processPool->releaseProcess($pipe);
                $connection->send('进程结束.');
                \Workerman\Worker::$globalEvent->offReadable($process);
            } else {
                $connection->send($output);
            }
        });
        return true;
    } else {
        return $connection->send('服务繁忙,请稍后重试.');
    }
};

\Workerman\Worker::runAll();

Testing

A simple command.php script that prints a message five times was created to verify the setup. The server is started with php start.php start, and a WebSocket testing tool is used to send a JSON payload containing the command /usr/bin/php8.2 command.php. The output streams back to the client in real time.

<?php
for ($i = 0; $i < 5; $i++) {
    sleep(1);
    echo '测试' . $i . PHP_EOL;
}

Running pstree -ap | grep -C 20 /usr/bin/php8.2 shows up to five concurrent processes, each exiting automatically after the script finishes.

Conclusion

By combining Workerman, popen, and a WebSocket front‑end (e.g., xterm.js), you can build a functional web‑SSH service. The same pattern can be extended to other scenarios such as launching ThinkPHP queue workers or any long‑running CLI tasks.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

WebSocketPHPWorkermanpopenAsyncProcess
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.