首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Stream 流包裝器深度解析:從基礎到自定義協議

     編輯:PHP 相關知識

前言

PHP Stream(流)是 PHP 4.3.0 引入的強大抽象層,統一了檔案、網路、壓縮等類檔案操作介面。善用 Stream 能大幅提升開發效率,甚至實現虛擬檔案系統、雲存儲透明訪問等高階功能。本文系統解析 Stream 核心概念、內建包裝器、上下文控制、過濾器鏈,並預告自定義包裝器開發。

Stream 基礎概念

什麼是 Stream?

Stream 是一個具有流式行為的資源物件:可線性讀寫、可用 fseek() 跳轉位置。每個 Stream 都有對應的「包裝器」處理特定協議與編碼。

Stream URI 格式

<scheme>://<target>
# 範例
file:///path/to/file.txt
https://example.com/api
compress.zlib://data.gz
php://input
phar://archive.phar/file.php
  • <scheme>:包裝器名稱(協議)
  • <target>:由包裝器語法定義的目標資源

預設包裝器

PHP 預設使用 file://,因此 readfile('/path/file') 等同於 readfile('file:///path/file')。

查詢系統支援的 Stream 功能

<?php
print_r(stream_get_transports()); // 傳輸層:tcp, udp, unix, ssl, tls...
print_r(stream_get_wrappers());   // 包裝器:file, http, ftp, compress.zlib, php, data, glob, zip, phar...
print_r(stream_get_filters());    // 過濾器:zlib.*, bzip2.*, convert.iconv.*, string.*, mcrypt.*...
?>

典型輸出範例

Array
(
    [0] => tcp
    [1] => udp
    [2] => unix
    [3] => udg
    [4] => ssl
    [5] => sslv3
    [6] => sslv2
    [7] => tls
)

Array
(
    [0] => https
    [1] => ftps
    [2] => compress.zlib
    [3] => compress.bzip2
    [4] => php
    [5] => file
    [6] => glob
    [7] => data
    [8] => http
    [9] => ftp
    [10] => zip
    [11] => phar
)

Array
(
    [0] => zlib.*
    [1] => bzip2.*
    [2] => convert.iconv.*
    [3] => string.rot13
    [4] => string.toupper
    [5] => string.tolower
    [6] => string.strip_tags
    [7] => convert.*
    [8] => consumed
    [9] => dechunk
    [10] => mcrypt.*
    [11] => mdecrypt.*
)

php:// 內建包裝器詳解

標準 I/O 流

php://input:原始 POST 資料讀取

關鍵用途:讀取非 application/x-www-form-urlencoded 的 POST 主體(如 JSON、XML、原始資料)。$_POST 僅解析表單資料。

<?php
// 測試:curl -d "Hello World" -d "foo=bar&name=John" https://localhost/test.php

// $_POST 只能獲取表單欄位
print_r($_POST);
/* Array ( [foo] => bar [name] => John ) */

// php://input 獲取完整原始主體
echo file_get_contents('php://input');
/* Hello World&foo=bar&name=John */
?>

php://memory 與 php://temp:暫存資料流

包裝器對應資源模式
php://stdin標準輸入唯讀
php://stdout標準輸出唯寫
php://stderr標準錯誤輸出唯寫
包裝器儲存位置適用場景
php://memory記憶體小量暫存資料、高速讀寫
php://temp記憶體(小量)→ 暫存檔(大量)不確定大小的暫存資料
<?php
// 寫入暫存流
$stream = fopen('php://temp', 'r+');
fwrite($stream, "臨時資料\n第二行");
rewind($stream);
echo stream_get_contents($stream); // 讀取全部
fclose($stream);
?>

php://filter:元包裝器/過濾器鏈

在開啟流時套用過濾器,支援讀寫雙向、多重串聯。

<?php
// 寫入時自動 ROT13 編碼
file_put_contents(
    "php://filter/write=string.rot13/resource=file:///path/to/file.txt",
    "Hello World"
);

// 讀取時:先大寫再 ROT13(管道串聯)
readfile("php://filter/read=string.toupper|string.rot13/resource=https://www.google.com");
?>

可用字串過濾器

  • string.rot13 - ROT13 編碼
  • string.toupper / string.tolower - 大小寫轉換
  • string.strip_tags - 移除 HTML 標籤
  • convert.iconv.* - 字元編碼轉換(如 convert.iconv.UTF-8/ISO-8859-1)
  • convert.base64-encode / convert.base64-decode - Base64 編解碼

Stream Context:修改包裝器行為

Context 是一組參數選項,用於自定義包裝器的具體行為(如 HTTP Header、SSL 驗證、FTP 模式等)。

HTTP Context 範例:無 cURL 發送 POST 請求

<?php
$opts = [
    'http' => [
        'method' => 'POST',
        'header' => "Auth: SecretAuthToken\r\n" .
                    "Content-type: application/x-www-form-urlencoded\r\n" .
                    "Content-length: " . strlen("Hello World"),
        'content' => 'Hello World',
        'timeout' => 10,
        'follow_location' => 1,
        'max_redirects' => 3,
    ]
];

// 設定預設 context
$default = stream_context_get_default($opts);

// 後續所有 https:// 流自動套用上述選項
$response = file_get_contents('https://localhost/api/endpoint');

// 或建立獨立 context 交替使用
$altContext = stream_context_create($otherOpts);
$response2 = file_get_contents('https://localhost/api/other', false, $altContext);
?>

常用 HTTP Context 選項

選項說明預設值
methodHTTP 方法GET
header額外 Header(字串或陣列)無
content請求主體資料無
user_agentUser-Agent 字串PHP/version
timeout連線/讀取超時(秒)ini 設定
follow_location是否跟隨重導向1
max_redirects最大重導向次數20
protocol_versionHTTP 協定版本1.0
ignore_errors錯誤狀態碼仍返回內容false

SSL Context 選項(HTTPS 關鍵)

<?php
$sslOpts = [
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
        'cafile' => '/path/to/ca-bundle.crt',
        'capath' => '/etc/ssl/certs/',
        'local_cert' => '/path/to/client.pem',
        'passphrase' => 'cert_password',
        'allow_self_signed' => false,
        'crypto_method' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
    ]
];

$context = stream_context_create(['http' => [], 'ssl' => $sslOpts['ssl']]);
$response = file_get_contents('https://secure-api.example.com', false, $context);
?>

Stream 過濾器:資料處理管道

過濾器可掛載到讀寫流上,實現資料的即時轉換。

掛載過濾器

<?php
$stream = fopen('data.txt', 'r');

// 掛載讀取過濾器
stream_filter_append($stream, 'string.toupper'); // 轉大寫
stream_filter_append($stream, 'zlib.inflate');   // 解壓縮

// 或使用 php://filter 包裝器(僅限開啟時)
$filtered = fopen('php://filter/read=string.rot13/resource=data.txt', 'r');
?>

自定義過濾器開發

<?php
class CustomFilter extends php_user_filter {
    public function filter($in, $out, &$consumed, $closing) {
        while ($bucket = stream_bucket_make_writeable($in)) {
            // 處理資料
            $bucket->data = str_rot13($bucket->data); // 範例:ROT13
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON; // PSFS_FEED_ME / PSFS_ERR_ON_ERROR
    }
}

// 註冊
stream_filter_register('custom.rot13', 'CustomFilter');

// 使用
$stream = fopen('php://filter/read=custom.rot13/resource=data.txt', 'r');
?>

實戰應用場景

1. 虛擬檔案系統:雲存儲透明訪問

為 AWS S3、Google Cloud Storage、阿里云 OSS 開發 s3://、gs://、oss:// 包裝器,應用程式無修改即可遷移至雲端。

2. 大檔案處理:記憶體高效讀寫

<?php
// 逐行處理大型 CSV,不載入記憶體
$stream = fopen('php://filter/read=convert.iconv.BIG5/UTF-8/resource=large.csv', 'r');
while (($row = fgetcsv($stream)) !== false) {
    processRow($row);
}
fclose($stream);
?>

3. 標準輸入輸出管道:CLI 工具鏈

<?php
// cat data.json | php process.php | jq .
$input = fopen('php://stdin', 'r');
$output = fopen('php://stdout', 'w');

while (($line = fgets($input)) !== false) {
    $data = json_decode($line, true);
    $result = process($data);
    fwrite($output, json_encode($result) . "\n");
}
?>

4. 壓縮資料流透明處理

<?php
// 讀取 gzip 檔案無需解壓縮到磁碟
$fp = fopen('compress.zlib://large.log.gz', 'r');
while (!feof($fp)) {
    echo fread($fp, 8192);
}
fclose($fp);

// 寫入 gzip
$fp = fopen('compress.zlib://output.log.gz', 'w');
fwrite($fp, $largeData);
fclose($fp);
?>

Stream 相關核心函數速查

函數用途
stream_wrapper_register()註冊自定義包裝器
stream_wrapper_unregister()取消註冊包裝器
stream_wrapper_restore()恢復內建包裝器
stream_context_create()建立 context
stream_context_get_default()獲取/設定預設 context
stream_context_set_option()設定 context 選項
stream_filter_register()註冊自定義過濾器
stream_filter_append/prepend()掛載過濾器到流
stream_get_meta_data()獲取流中繼資料
stream_copy_to_stream()高效流複製
stream_socket_client/server()底層 Socket 操作

總結與下一步

PHP Stream 提供了統一、可擴展的 I/O 抽象層。掌握內建包裝器(php://、compress.*、https://)、Context 控制、過濾器鏈,能解決 90% 的資料流處理需求。下一步進階方向:開發自定義包裝器(實現 s3://、db:// 等虛擬協議),將在後續文章詳細介紹。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved