You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP表单实现ping命令CLI式实时输出的技术求助

Hey there! Let's figure out how to get that real-time, CLI-like output for your ping tool. The issue with your current code is that shell_exec() waits for the entire ping command to finish before spitting out all the output at once—so no live updates. Let's break down two reliable ways to fix this:


Method 1: Real-time Output Directly in the Same Page

We'll use PHP's process control functions to capture the command's output line-by-line, and force the browser to render each line as it comes in.

First, update your PHP code like this:

<?php
// Disable output buffering to ensure real-time sends
ini_set('output_buffering', '0');
ini_set('implicit_flush', true);

if(isset($_REQUEST['submit'])) {
    $ipaddress = $_REQUEST['ipaddress'];
    // Always escape user input to prevent command injection!
    $safeIp = escapeshellarg($ipaddress);

    // Set up pipes to capture the command's streams
    $descriptorspec = [
        0 => ["pipe", "r"],  // Stdin (we won't use this)
        1 => ["pipe", "w"],  // Stdout (ping's normal output)
        2 => ["pipe", "w"]   // Stderr (error messages)
    ];

    $process = proc_open("ping -c 5 $safeIp", $descriptorspec, $pipes);

    if (is_resource($process)) {
        fclose($pipes[0]); // Close stdin—ping doesn't need input

        // Read stdout line by line
        while (!feof($pipes[1])) {
            $line = fgets($pipes[1]);
            echo "<pre>" . htmlspecialchars($line) . "</pre>";
            // Flush buffers to send output to the browser immediately
            ob_flush();
            flush();
            // Small delay to mimic CLI pacing (optional)
            usleep(100000);
        }

        // Read and display any error messages
        while (!feof($pipes[2])) {
            $line = fgets($pipes[2]);
            echo "<pre style='color: #dc2626;'>" . htmlspecialchars($line) . "</pre>";
            ob_flush();
            flush();
        }

        // Clean up resources
        fclose($pipes[1]);
        fclose($pipes[2]);
        proc_close($process);
    }
}
?>

Key Notes for This Method:

  • proc_open() is the star here—it lets us interact with the running ping process in real-time, unlike shell_exec() which blocks until completion.
  • escapeshellarg() is non-negotiable—it prevents malicious users from injecting arbitrary commands (e.g., 8.8.8.8; rm -rf / would be harmless with this).
  • If your server uses Nginx, you might need to disable fastcgi_buffering for this script to ensure output isn't buffered server-side.

Method 2: Server-Sent Events (SSE) for Cleaner Async Output

If you want a more modern, non-blocking experience (the page doesn't hang while waiting for output), SSE is a great option. Here's how to set it up correctly (since your earlier attempts likely missed a critical detail):

Step 1: Update Your Frontend HTML

<form id="pingForm">
    <input type="text" name="ipaddress" id="ipaddress" placeholder="Enter IP"/>
    <button type="submit">Run Ping</button>
</form>
<div id="outputContainer"></div>

<script>
document.getElementById('pingForm').addEventListener('submit', function(e) {
    e.preventDefault();
    const ip = document.getElementById('ipaddress').value;
    const output = document.getElementById('outputContainer');
    output.innerHTML = ''; // Clear previous output

    // Connect to the SSE endpoint
    const sseSource = new EventSource(`ping-sse.php?ip=${encodeURIComponent(ip)}`);

    // Handle incoming messages
    sseSource.onmessage = function(event) {
        if (event.data === '[PING_COMPLETE]') {
            sseSource.close();
            return;
        }
        const lineElement = document.createElement('pre');
        lineElement.textContent = event.data;
        output.appendChild(lineElement);
    };

    // Handle errors
    sseSource.onerror = function(error) {
        console.error('SSE Connection Error:', error);
        sseSource.close();
        output.innerHTML += '<pre style="color: #dc2626;">Something went wrong—please try again.</pre>';
    };
});
</script>

Step 2: Create the SSE Backend (ping-sse.php)

<?php
// Set required SSE headers—this is probably what you missed earlier!
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('Access-Control-Allow-Origin: *'); // Optional, if needed for local testing

if (!isset($_GET['ip'])) {
    echo "data: Please provide a valid IP address\n\n";
    exit;
}

$safeIp = escapeshellarg($_GET['ip']);
$descriptorspec = [
    0 => ["pipe", "r"],
    1 => ["pipe", "w"],
    2 => ["pipe", "w"]
];

$process = proc_open("ping -c 5 $safeIp", $descriptorspec, $pipes);

if (is_resource($process)) {
    fclose($pipes[0]);

    // Stream stdout to the frontend
    while (!feof($pipes[1])) {
        $line = fgets($pipes[1]);
        // SSE requires strict format: "data: [content]\n\n"
        echo "data: " . htmlspecialchars($line) . "\n\n";
        ob_flush();
        flush();
        usleep(100000);
    }

    // Stream stderr if any errors occur
    while (!feof($pipes[2])) {
        $line = fgets($pipes[2]);
        echo "data: [ERROR] " . htmlspecialchars($line) . "\n\n";
        ob_flush();
        flush();
    }

    // Cleanup
    fclose($pipes[1]);
    fclose($pipes[2]);
    proc_close($process);
}

// Send a completion signal to the frontend
echo "data: [PING_COMPLETE]\n\n";
ob_flush();
flush();
?>

Key Notes for SSE:

  • The response headers are critical—without text/event-stream, the browser won't recognize this as an SSE connection.
  • Each message must follow the data: [content]\n\n format—two newlines at the end to signal the end of a message.
  • Like the first method, ensure your server isn't buffering the output (disable fastcgi_buffering in Nginx if needed).

Whichever method you choose, don't skip the input sanitization with escapeshellarg()—it's a basic security measure that prevents command injection attacks.

内容的提问来源于stack exchange,提问作者user3206138

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:44:14