本文目录导读:

- 什么是PHP流(Streams)?
- 上下文选项(Context Options)
- 上下文参数(Context Parameters)
- 自定义流包装器
- 实战:完整HTTP客户端(带错误处理)
- 流 vs Curl:如何选择?
- 总结知识图谱
在PHP中,流(Streams) 和上下文选项(Context Options) 是非常强大但常被低估的功能,它们为PHP提供了统一的文件、网络、压缩等资源访问抽象层。
以下是关于PHP流与上下文选项的详细解释和实战指南。
什么是PHP流(Streams)?
简单说,流是一个资源对象,它表现出可流式的行为(可读、可写、可查找),PHP将所有类似文件的操作(读文件、写文件、HTTP请求、FTP连接、压缩文件、内存数据等)都抽象为“流”。
流式操作的特点
- 低内存占用:不需要一次性把整个文件加载到内存,可以边读边处理(适合大文件)。
- 统一接口:
fopen,fread,fwrite,fclose可应用于几乎任何数据源。
常见的流封装协议(Wrapper)
PHP内置了许多“流包装器”,通过指定协议来访问不同类型的资源:
| 协议 | 用途 | 示例 |
|---|---|---|
file:// |
本地文件系统(默认) | fopen('file:///tmp/test.txt', 'r') |
http:// / https:// |
HTTP/HTTPS 请求 | fopen('http://example.com', 'r') |
ftp:// / ftps:// |
FTP 连接 | fopen('ftp://user:pass@host/file', 'w') |
php:// |
访问各种I/O流 | php://stdin, php://output, php://memory |
compress.zlib:// |
读取/写入gzip压缩文件 | fopen('compress.zlib://file.gz', 'r') |
data:// |
内联数据(类似data URI) | fopen('data://text/plain;base64,...', 'r') |
phar:// |
访问Phar归档包内的文件 | fopen('phar://app.phar/config.php', 'r') |
极其实用的 php:// 流:
php://stdin/php://stdout/php://stderr:标准输入/输出/错误php://input:读取HTTP POST请求的原始body(常用于API接收JSON)php://output:写入HTTP响应body(相当于echo)php://memory/php://temp:虚拟临时内存/文件存储
// 将POST原始请求体(如JSON)转为数组
$json = file_get_contents('php://input');
$data = json_decode($json, true);
// 向内存写入临时数据(无需真实文件)
$temp = fopen('php://memory', 'r+');
fwrite($temp, 'Hello Stream!');
rewind($temp);
echo fread($temp, 1024); // 输出: Hello Stream!
上下文选项(Context Options)
当使用流函数(fopen, file_get_contents, stream_context_create 等)时,可以通过流上下文(Stream Context) 来修改协议的行为。
流上下文是一个关联数组,包含:
- 选项:针对特定协议的配置(如HTTP头、超时、代理)
- 参数:通知回调、读/写缓冲区大小等
如何使用上下文
// 1. 创建上下文数组
$options = [
'http' => [
'method' => 'GET',
'header' => "User-Agent: MyApp/1.0\r\nAccept: application/json",
'timeout' => 10
]
];
// 2. 创建上下文资源
$context = stream_context_create($options);
// 3. 将上下文传递给流函数
$result = file_get_contents('https://api.example.com/data', false, $context);
常见协议选项详解
HTTP/HTTPS 常用选项
| 选项 | 说明 | 示例值 |
|---|---|---|
method |
请求方法 | 'GET', 'POST', 'DELETE' |
header |
请求头(多行用\r\n分隔) |
"Content-Type: application/json\r\nAuthorization: Bearer xxx" |
content |
POST请求的body | json_encode(['key' => 'value']) |
timeout |
超时秒数(float) | 0 |
proxy |
HTTP代理 | 'tcp://proxy.example.com:8080' |
user_agent |
User-Agent字符串 | 'Mozilla/5.0' |
ignore_errors |
忽略HTTP错误码(如404) | true |
POST请求实战:
$data = ['name' => 'Alice', 'email' => 'alice@example.com'];
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode($data),
'timeout' => 15
]
];
$context = stream_context_create($options);
$response = file_get_contents('https://httpbin.org/post', false, $context);
FTP 常用选项
| 选项 | 说明 |
|---|---|
overwrite |
覆盖已有文件 |
resume_pos |
从指定位置继续上传/下载 |
proxy |
FTP代理 |
SSL/TLS 选项(用于https://或ftps://)
| 选项 | 说明 | 示例值 |
|---|---|---|
verify_peer |
验证服务器证书 | true(默认) |
verify_peer_name |
验证主机名匹配证书 | true |
cafile |
CA证书文件路径(用于自定义根证书) | '/path/to/ca.pem' |
local_cert |
客户端证书路径 | '/path/to/client.pem' |
passphrase |
私钥密码 | 'secret' |
安全HTTP请求:
$options = [
'ssl' => [
'verify_peer' => true,
'cafile' => '/etc/ssl/certs/ca-certificates.crt',
'verify_depth' => 5
]
];
$context = stream_context_create($options);
$data = file_get_contents('https://secure-api.example.com', false, $context);
上下文参数(Context Parameters)
除了协议选项,上下文还可以设置参数,用于控制流的行为和通知。
| 参数 | 说明 | 用途 |
|---|---|---|
notification |
流事件回调函数 | 监控进度、重定向等 |
blocking |
阻塞(true)或非阻塞(false)模式 |
异步I/O |
进度通知回调(非常实用!)
function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
switch ($notification_code) {
case STREAM_NOTIFY_FILE_SIZE_IS:
echo "文件大小: $bytes_max 字节\n";
break;
case STREAM_NOTIFY_PROGRESS:
if ($bytes_max > 0) {
$percent = round($bytes_transferred / $bytes_max * 100);
echo "下载进度: $percent%\r";
}
break;
case STREAM_NOTIFY_COMPLETED:
echo "\n下载完成!\n";
break;
case STREAM_NOTIFY_FAILURE:
echo "错误: $message\n";
break;
}
}
$params = ['notification' => 'stream_notification_callback'];
$context = stream_context_create([], $params);
$data = file_get_contents('https://cdn.example.com/large-file.zip', false, $context);
自定义流包装器
如果内建协议不够用,可以注册自己的流包装器。
class MyStreamWrapper {
private $position = 0;
private $data = '';
public function stream_open($path, $mode, $options, &$opened_path) {
$this->data = "Hello from custom stream!";
return true;
}
public function stream_read($count) {
$ret = substr($this->data, $this->position, $count);
$this->position += strlen($ret);
return $ret;
}
public function stream_eof() {
return $this->position >= strlen($this->data);
}
public function stream_stat() {
return ['size' => strlen($this->data)];
}
}
// 注册协议
stream_wrapper_register('my', 'MyStreamWrapper');
// 使用
$fp = fopen('my://something', 'r');
echo fread($fp, 1024); // 输出: Hello from custom stream!
实战:完整HTTP客户端(带错误处理)
function http_get($url, $headers = []) {
$header_str = '';
foreach ($headers as $key => $value) {
$header_str .= "$key: $value\r\n";
}
$options = [
'http' => [
'method' => 'GET',
'header' => $header_str,
'timeout' => 5,
'ignore_errors' => true // 允许捕获非2xx响应
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
'cafile' => '/etc/ssl/certs/ca-certificates.crt'
]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
if ($response === false) {
$error = error_get_last();
throw new \RuntimeException("HTTP请求失败: " . ($error['message'] ?? '未知错误'));
}
// 获取响应头
$response_headers = $http_response_header ?? [];
$status_code = 0;
if (preg_match('#HTTP/\d+\.\d+ (\d+)#', $response_headers[0] ?? '', $m)) {
$status_code = (int) $m[1];
}
return [
'status' => $status_code,
'headers' => $response_headers,
'body' => $response
];
}
// 使用
$result = http_get('https://api.github.com', ['User-Agent' => 'PHP-Streams']);
echo $result['status']; // 200
流 vs Curl:如何选择?
| 场景 | 推荐方案 |
|---|---|
| 简单GET/POST请求 | file_get_contents + 上下文(最简洁) |
| 复杂HTTP(cookie、重定向控制、多请求) | cURL(功能更全) |
| 大文件下载/上传 | 流(可用fread分批处理) |
| FTP传输 | 流(内建支持,无需扩展) |
| 异步/并发请求 | cURL多处理 或 Guzzle |
| 内存中的数据处理 | php://memory 或 php://temp |
对于简单的HTTP请求和几乎所有文件操作,流+上下文是PHP最原生的方案,无需额外扩展,复杂HTTP任务请使用cURL。
总结知识图谱
流 (Streams)
├── 封装协议
│ ├── file://, http://, ftp://
│ ├── php:// (stdin, input, memory, temp)
│ └── compress.zlib://, data://
├── 流函数
│ ├── fopen, fread, fwrite, fclose
│ ├── file_get_contents, file_put_contents
│ └── stream_get_contents, fgets, fgetcsv
└── 上下文 (Context)
├── 协议选项
│ ├── http (method, header, content, timeout)
│ ├── ssl (verify_peer, cafile)
│ └── ftp (overwrite, proxy)
└── 参数
└── notification (进度回调)
掌握流和上下文,你就能用最少的代码完成从本地文件操作到远程API调用、大文件上传监控等一系列任务,是PHP开发者的必备技能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播