Stream(流)是 PHP 處理 I/O 的核心抽象,源自 UNIX 管道概念。本文從基本概念切入,示範 Socket 通訊、HTTP 上下文、內建與自訂過濾器,並簡述 Stream Wrapper 封裝協議。
file://、https://、ftp://、php://、data://、zlib:// 等。stream_context_create() 設定協定選項(HTTP Header、SSL 驗證、FTP 登入等)。<?php
$post = ['author'=>'Gonn', 'mail'=>'gonn@example.com', 'text'=>'Hello'];
$data = http_build_query($post);
$fp = stream_socket_client("tcp://example.com:80", $errno, $errstr, 5);
if (!$fp) die("連線失敗: $errstr");
$req = "POST /api/comment HTTP/1.1\r\n";
$req .= "Host: example.com\r\n";
$req .= "Content-Type: application/x-www-form-urlencoded\r\n";
$req .= "Content-Length: " . strlen($data) . "\r\n";
$req .= "Connection: close\r\n\r\n";
$req .= $data . "\r\n";
fwrite($fp, $req);
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
?>
等同於 fsockopen,但 stream_socket_client 支援更多協定(ssl://、udp://、unix://)。
<?php
$opts = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($data),
'content' => $data,
'timeout' => 30
]
];
$context = stream_context_create($opts);
$result = file_get_contents('https://example.com/api/comment', false, $context);
?>
file_get_contents、fopen、copy 等函數均接受 $context 參數,統一介面操作不同協定。
<?php
$fp = fopen('test.txt', 'w+');
// 掛載 rot13 過濾器於寫入流
stream_filter_append($fp, 'string.rot13', STREAM_FILTER_WRITE);
fwrite($fp, "Hello World\n");
rewind($fp);
fpassthru($fp); // 輸出:Uryyb Jbeyq
fclose($fp);
// 列出所有內建過濾器
print_r(stream_get_filters());
/* 輸出範例
Array (
[0] => convert.iconv.*
[1] => string.rot13
[2] => string.toupper
[3] => string.tolower
[4] => string.strip_tags
[5] => zlib.*
[6] => bzip2.*
...
)
*/
<?php
class MD5_Filter extends php_user_filter {
public function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = md5($bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
// 回呼日誌函數
if (isset($this->params['log_callback']) && is_callable($this->params['log_callback'])) {
call_user_func($this->params['log_callback'], $bucket->data);
}
return PSFS_PASS_ON;
}
}
stream_filter_register('string.md5', 'MD5_Filter');
// 使用
$logCb = function($data) {
file_put_contents('stream.log', date('Y-m-d H:i:s') . " MD5: $data\n", FILE_APPEND);
};
$fp = fopen('data.txt', 'w');
stream_filter_prepend($fp, 'string.md5', STREAM_FILTER_WRITE, ['log_callback' => $logCb]);
fwrite($fp, "敏感資料");
fclose($fp);
實作 stream_wrapper_register('myproto', 'MyProto_Handler'),即可讓 fopen('myproto://path')、file_get_contents('myproto://path') 使用自訂類別處理。適用於虛擬檔案系統、資料庫 Blob 存取、雲端儲介面統一等場景。
stream_context 簡化 HTTP/FTP/SSL 參數設定。