RRDtool 是強大的時間序列資料繪圖工具,但預設需輸出至檔案。透過 PHP 的 popen() 建立管道,可直接讀取 RRDtool 的標準輸出並以圖片串流回應客戶端,實現真正的動態圖表服務。
-(標準輸出)popen(command, 'r') 開啟讀取管道<?php
error_reporting(E_ALL);
// RRDtool 繪圖命令:注意 graph 後的 "-" 代表輸出到 stdout
$command = '/opt/rrdtool/bin/rrdtool graph - ' .
'--start=-86400 --end=-300 ' .
'--title="流量監控" --height=400 --width=800 ' .
'DEF:traffic_in="/var/lib/rrd/traffic_in.rrd":traffic_in:AVERAGE ' .
'AREA:traffic_in#FF0000:"入站流量" ' .
'2>&1'; // 將 stderr 導向 stdout 捕捉錯誤訊息
// 關閉 session 避免鎖定影響長時間執行
session_write_close();
// 執行命令並讀取輸出
$handle = popen($command, 'r');
$imageData = '';
while (!feof($handle)) {
$imageData .= fgets($handle, 4096);
}
$exitCode = pclose($handle);
// 錯誤處理
if ($exitCode !== 0 || empty($imageData)) {
header('Content-Type: text/plain; charset=utf-8');
die("RRDtool 執行失敗 (exit code: $exitCode)\n輸出:\n$imageData");
}
// 輸出 PNG 圖片
header('Content-Type: image/png');
header('Content-Length: ' . strlen($imageData));
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header('Cache-Control: public, max-age=300'); // 快取 5 分鐘
echo $imageData;
?>
| 技術點 | 說明 |
|---|---|
graph - | 指定輸出到標準輸出而非檔案 |
2>&1 | 將 stderr 重導向 stdout,確保錯誤訊息可被捕捉 |
session_write_close() | 釋放 session 鎖,避免並發請求阻塞 |
| 分塊讀取 | 使用 4KB 緩衝區平衡記憶體與效能 |
| 快取標頭 | 減少重複渲染負載,建議依資料更新頻率調整 max-age |
--font DEFAULT:12:/path/to/simhei.ttf 設定中文字型此模式同樣適用於其他命令列繪圖工具(如 gnuplot、Graphviz),或任何需動態產生二進位內容(PDF、Excel、圖片)的場景。