Linux 管道 (|) 讓指令間直接傳遞資料。PHP popen() 開啟管道至外部命令,回傳檔案指標,可像操作檔案一樣讀寫。本文示範管道讀取命令輸出、發送郵件、常見參數與注意事項。
resource popen(string $command, string $mode); // mode: 'r' 讀取輸出, 'w' 寫入輸入
// 關閉:pclose($fp)
ls -l)<?php
$fp = popen('/bin/ls -l -FN /etc', 'r');
if ($fp) {
while (!feof($fp)) {
echo fgets($fp, 4096) . '<br>';
}
pclose($fp);
}
?>
比 Socket 簡單,無需手寫 SMTP 協定交握。
<?php
$fp = popen('/usr/sbin/sendmail -t', 'w'); // -t 從郵件標頭解析收件者
if ($fp) {
$to = 'user@example.com';
$subject = '測試郵件';
$message = "Hello!\n這是管道發送的郵件。\n";
$headers = "From: sender@example.com\r\n";
$headers .= "Reply-To: sender@example.com\r\n";
$headers .= "Subject: $subject\r\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
fwrite($fp, $headers . $message);
fwrite($fp, "\n.\n"); // sendmail 結束標記
pclose($fp);
echo '郵件已送入佇列';
}
?>
| 方式 | 特性 | 適用場景 |
|---|---|---|
管道 popen | 雙向/單向資料流、類檔案操作、自動管理子進程 | 命令輸出讀取、簡單郵件發送、過濾器鏈 |
重導向 exec() + > file | 單向、輸出至檔案、需自行讀檔 | 長時間任務、需持久化輸出 |
Socket fsockopen/stream_socket_client | 完整 TCP 協定控制、需手寫應用層協定 | HTTP 請求、SMTP/IMAP/POP3、自定義協定 |
popen 預設阻塞,大量輸出需考慮非阻塞或 proc_open。/usr/sbin/sendmail) 確保可執行。escapeshellarg、escapeshellcmd)。popen 行為不同,建議改用 proc_open 或 COM 組件。PHPMailer、SwiftMailer 或 Symfony Mailer,支援 SMTP、SSL、附件、佇列。<?php
$descriptors = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];
$proc = proc_open('/usr/bin/sort', $descriptors, $pipes);
if (is_resource($proc)) {
fwrite($pipes[0], "c\na\nb\n");
fclose($pipes[0]);
echo stream_get_contents($pipes[1]); // a b c
fclose($pipes[1]);
proc_close($proc);
}
?>