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

深入理解 PHP Streams:從基礎包裝器到自定義協議的實戰指南

     編輯:PHP 綜合知識

什麼是 Stream?

Stream(流)是 PHP 4.3 引入的統一資源抽象層,將檔案、網路、壓縮、進程間通訊等「可讀寫、可定位」的資源統一為 scheme://target 形式,使用相同函數族(fopen/fread/fwrite/fseek 等)操作。

一、內建包裝器速查

print_r(stream_get_wrappers());
/*
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
)
*/
  • file:// 預設,本地檔案系統。
  • https:///https://、ftp:// 網路協議。
  • compress.zlib:///compress.bzip2:// 透明壓縮/解壓。
  • php:// 內部 I/O:stdin/stdout/stderr/input/memory/temp/filter。
  • data:// 內嵌資料(RFC 2397)。
  • phar:// PHP 封存檔。

二、php:// 關鍵用法

1. php://input —— 讀取原始 POST Body

curl -d "raw=data&foo=bar" https://localhost/input.php
// $_POST 只解析 application/x-www-form-urlencoded
echo file_get_contents('php://input'); // 取得完整原始字串

2. php://memory / php://temp —— 記憶體/臨時檔

$fp = fopen('php://temp', 'r+'); // 超過 2MB 自動落地臨時檔
fwrite($fp, "大量資料...");
rewind($fp);
echo stream_get_contents($fp);

3. php://filter —— 串聯過濾器

// 寫入時 ROT13 編碼
file_put_contents('php://filter/write=string.rot13/resource=file:///tmp/test.txt', 'Hello');

// 讀取時大寫 + ROT13
echo file_get_contents('php://filter/read=string.toupper|string.rot13/resource=https://example.com');

三、Stream Context(上下文)

Context 允許在不改變包裝器代碼的情況下修改行為(如 HTTP Header、SSL 選項、FTP 被動模式)。

HTTP POST 範例(無需 cURL)

$opts = [
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/x-www-form-urlencoded\r\n" .
                     "Authorization: Bearer TOKEN\r\n",
        'content' => http_build_query(['foo' => 'bar']),
        'timeout' => 10,
    ],
];
$ctx = stream_context_create($opts);
$resp = file_get_contents('https://api.example.com/endpoint', false, $ctx);

設定預設 Context

stream_context_set_default(['http' => ['timeout' => 5]]); // 全域生效

四、實戰場景

場景Stream 方案
大檔案分片上傳fopen('php://input') 邊讀邊寫磁碟,不佔記憶體
透明讀取 .gz 日誌fopen('compress.zlib:///var/log/app.log.gz')
無臨時檔處理上傳php://temp 當緩衝區
動態生成壓縮包下載php://output + zip:// 串流輸出
PaaS 無實體檔案系統自定義 s3://、gcs:// 包裝器,代碼零修改遷雲

五、自定義包裝器(進階)

實作 stream_wrapper_register() 介面:

class S3Wrapper {
    public $context;
    public function stream_open($path, $mode, $options, &$opened_path) { /* 連接 S3 */ return true; }
    public function stream_read($count) { /* 從 S3 讀取 */ return $data; }
    public function stream_write($data) { /* 寫入 S3 */ return strlen($data); }
    public function stream_tell() { return $this->position; }
    public function stream_eof() { return $this->position >= $this->size; }
    public function stream_seek($offset, $whence) { /* 定位 */ return true; }
    public function stream_stat() { return ['size'=>$this->size]; }
    public function url_stat($path, $flags) { return ['size'=>$this->size]; }
}
stream_wrapper_register('s3', 'S3Wrapper') or die('註冊失敗');
// 之後即可 fopen('s3://bucket/key', 'r')

六、最佳實務

  1. 優先使用內建包裝器,減少依賴。
  2. 大資料流採用 php://temp 避免記憶體爆炸。
  3. 網路請求統一用 Context 管理超時、重試、Header。
  4. 自定義包裝器隔離儲存細節,業務代碼保持 fopen/fread/fwrite 風格。

結語

Streams 是 PHP 最被低估的強大抽象。掌握它,能以極低成本解決檔案、網路、壓縮、雲儲存的統一存取問題。

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