PHP 4.3 引入統一流抽象層,所有檔案 I/O、網路通訊、壓縮處理均透過 php_stream 介面。本文解析 php_stream_open_wrapper 核心 API、11 種選項標記、流包裝器架構與實戰範例。
| 類別 | 典型函式 | 底層流類型 |
|---|---|---|
| fopen 包裝 | fopen(), file_get_contents(), file_put_contents(), file() | 檔案/URI 方式指定遠端資源 |
| 傳輸/通訊 | fsockopen(), stream_socket_client(), stream_socket_server() | 基於 Socket 的循序 I/O |
| 目錄流 | opendir(), scandir(), dir() | 目錄列舉 |
| 特殊流 | tmpfile(), popen(), proc_open() | 暫存檔、管道、程序通訊 |
所有流統一儲存於 php_stream 結構體。
php_stream *php_stream_open_wrapper(
const char *path, // 路徑/URL
const char *mode, // 開啟模式 (r/w/a/r+/wb 等)
int options, // 選項標記位域
char **opened_path // 輸出:實際開啟路徑 (可為 NULL)
);
| 常數 | 含義 | 適用場景 |
|---|---|---|
USE_PATH | 套用 include_path 解析相對路徑 | fopen() 第三參數為 true 時自動設定 |
STREAM_USE_URL | 僅允許開啟遠端 URL | 強制遠端存取,忽略本地檔案 |
ENFORCE_SAFE_MODE | 強制檢查 safe_mode (已棄用) | 歷史相容,PHP 5.4+ 移除 safe_mode |
REPORT_ERRORS | 開啟失敗時產生錯誤訊息 | 預設建議開啟,除非自行處理錯誤 |
STREAM_MUST_SEEK | 要求流可隨機存取 (seekable) | 需 fseek() 的場景,Socket 會失敗 |
STREAM_WILL_CAST | 預告將轉換為 stdio/posix 描述符 | 需 fileno() 或傳給 C 庫時 |
STREAM_ONLY_GET_HEADERS | 僅取得 HTTP 標頭,不下載內容 | HTTP 包裝器專用,填充 $http_response_header |
STREAM_DISABLE_OPEN_BASEDIR | 繞過 open_basedir 檢查 | 內部可信操作,謹慎使用 |
STREAM_OPEN_PERSISTENT | 持久化分配,註冊至持久清單 | 長連線、連線池場景 |
IGNORE_PATH | 不搜尋 include_path | 明確指定絕對路徑時 |
IGNORE_URL | 忽略所有 URL 包裝器,僅開啟本地檔案 | 安全敏感操作,防止 SSRF |
PHP_FUNCTION(sample5_fopen) {
php_stream *stream;
char *path, *mode;
int path_len, mode_len;
int options = ENFORCE_SAFE_MODE | REPORT_ERRORS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
&path, &path_len, &mode, &mode_len) == FAILURE) {
return;
}
stream = php_stream_open_wrapper(path, mode, options, NULL);
if (!stream) {
RETURN_FALSE;
}
// 將 php_stream 轉為 PHP 資源變數
php_stream_to_zval(stream, return_value);
}
流開啟流程:
php_stream_open_wrapper(path, mode, options, &opened_path)
│
▼
解析 URL scheme:// (file://, https://, ftp://, php://, zlib://, bzip2://, ssh2:// 等)
│
▼
在已註冊包裝器表中查找 php_stream_wrapper
│
▼
呼叫 wrapper->wops->stream_opener(wrapper, filename, mode, options, &opened_path, context)
│
▼
建立 php_stream,設定 stream->ops = wrapper->wops->stream_ops
│
▼
回傳 php_stream*
| Scheme | 用途 | 支援操作 |
|---|---|---|
file:// | 本地檔案系統 | 讀/寫/Seek/Stat/目錄 |
https://, https:// | HTTP/HTTPS 請求 | 讀/標頭/POST/SSL |
ftp://, ftps:// | FTP/FTPS | 讀/寫/目錄/SSL |
php:// | 特殊 I/O (stdin/stdout/stderr/memory/temp/filter) | 讀/寫/過濾器 |
zlib://, bzip2:// | 壓縮流 | 讀/寫/壓縮解壓 |
ssh2:// | SSH2 (需 pecl/ssh2) | Shell/SCP/SFTP |