文章目录
PHP 伪协议,在 PHP 官方文档中被更精确地定义为“流包装器(Stream Wrappers)”,是 PHP 语言中一项核心且强大的功能。它们提供了一种统一的抽象层,使得 PHP 的文件系统函数(如
fopen()
、
file_get_contents()
、
include()
等)能够以一致的方式与各种数据源进行交互 。这些数据源不仅限于本地文件,还包括远程 URL、内存中的数据、压缩文件内部的内容,甚至是标准输入/输出流 。
流包装器通过 scheme://
的 URL 风格语法来指定,例如 file://
用于访问本地文件系统,http://
用于发起 HTTP 请求,而 php://
则提供了对 PHP 内部 I/O 流的访问 。PHP 内置了多种流包装器,极大地增强了其在数据处理方面的灵活性。此外,PHP 还允许开发者通过 stream_wrapper_register()
函数注册自定义的流包装器,进一步扩展了其功能 。
流包装器的核心价值在于其提供了一种统一的数据访问接口,显著简化了 PHP 应用程序处理异构数据源的复杂性。开发者无需针对不同类型的数据源编写独立的逻辑,只需通过相应的流包装器即可实现数据的读取或写入,从而有效提高了开发效率和代码的可维护性 。
PHP 伪协议(流包装器)详解
file://
:本地文件系统访问
file://
是 PHP 默认的本地文件系统访问包装器,在文件路径中通常可以被隐式省略。它允许 PHP 函数直接读取、写入、创建或操作服务器上的本地文件 。
功能与用例:
file://
用于访问服务器上的本地文件系统。例如,可以使用 file_get_contents()
函数读取文件的全部内容到字符串变量中 。fopen()
函数结合循环可以逐行读取文件 。
实战举例:
- 读取文件内容:
<?php $fileContents = file_get_contents('file.txt'); echo $fileContents; ?>
此代码将 file.txt
的所有内容作为字符串返回 。
- 逐行读取文件:
<?php if (file_exists('file.txt')) { $file = fopen('file.txt', 'r'); while (($line = fgets($file))!== false) { echo $line. '<br>'; } fclose($file); } else { echo 'File does not exist'; } ?>
此代码检查文件是否存在,以读取模式 ('r'
) 打开文件,使用 `fgets` 逐行读取,然后关闭文件 。
- 创建新文件:
<?php if (!file_exists('log.txt')) { $file = fopen("log.txt", "w"); fclose($file); } else { echo 'File exists already'; } ?>
此代码检查文件是否存在,如果不存在则以写入模式 ('w'
) 创建 `log.txt` 文件 。
- 写入文件:
<?php if (file_exists('log.txt')) { $file = fopen("log.txt", "w"); fwrite($file, "This is a new log entry.\n"); fclose($file); } else { echo 'File does not exist.'; } ?>
此代码以写入模式打开 log.txt
并写入内容,会覆盖原有内容 。
- 追加内容到文件:
<?php if (file_exists('log.txt')) { $file = fopen("log.txt", "a"); fwrite($file, "This is an appended log entry.\n"); fclose($file); } else { echo 'File does not exist.'; } ?>
此代码以追加模式打开 log.txt
,将新内容添加到文件末尾而不覆盖原有内容 。
http://
和 https://
:远程 URL 访问
http://
和 https://
包装器允许 PHP 应用程序发起 HTTP 或 HTTPS 请求,用于获取远程资源 。这在现代 Web 应用中非常普遍,例如调用外部 API、获取远程图片、加载远程脚本或数据等 。
功能与用例:
这些包装器用于通过 HTTP 或 HTTPS 协议从远程服务器获取内容。
实战举例:
- 获取远程网页内容:
<?php $html = file_get_contents("http://example.com/data.json"); echo $html; ?>
此代码将从 http://example.com/data.json
获取的 JSON 数据作为字符串返回 。
php://
:I/O 流访问
php://
包装器提供了一种访问 PHP 各种内部 I/O 流的特殊机制。这些流包括标准输入/输出、内存流和临时文件流,使得 PHP 能够以编程方式处理各种数据输入和输出,而无需实际的文件操作 。
php://filter
php://filter
包装器不直接执行文件,而是用于在数据流通过时应用各种过滤器,对数据进行转换 。最常见的用途是进行编码/解码(如 base64-encode
、base64-decode
)或压缩等操作 。
功能与用例:
php://filter
用于对数据流进行转换,例如 Base64 编码或解码。它通过 resource
参数指定要过滤的流,并通过 read
或 write
参数指定要应用的过滤器 。
实战举例:
- 读取并转换为大写:
<?php /* 这将把 www.example.com 的内容全部输出为大写 */ readfile("php://filter/read=string.toupper/resource=http://www.example.com"); ?>
此代码通过 string.toupper
过滤器将 `http://www.example.com` 的内容转换为大写并输出 。
- 读取并转换为大写后进行 ROT13 编码:
<?php /* 这将执行与上面相同的操作,但还会进行 ROT13 编码 */ readfile("php://filter/read=string.toupper|string.rot13/resource=http://www.example.com"); ?>
此代码在转换为大写后,再通过 string.rot13
过滤器进行 ROT13 编码 。
- 写入时进行 ROT13 编码:
<?php /* 这将通过 rot13 过滤器过滤字符串 "Hello World",然后写入当前目录的 example.txt */ file_put_contents("php://filter/write=string.rot13/resource=example.txt","Hello World"); ?>
此代码在写入 example.txt
之前,将字符串 “Hello World” 通过 `string.rot13` 过滤器进行编码 。
php://input
php://input
允许读取 HTTP 请求体中的原始 POST 数据,而无需依赖 $_POST
超全局变量($_POST
仅处理 application/x-www-form-urlencoded
或 multipart/form-data
格式的数据)。这对于处理非标准格式的 POST 数据,如 JSON 或 XML 请求体,非常有用 。
功能与用例:
php://input
用于读取 HTTP 请求的原始 POST 数据,特别适用于接收 JSON 或 XML 等非表单数据 。
实战举例:
- 获取 JSON 格式的 POST 数据:
<?php // 获取 JSON 内容 $json = file_get_contents('php://input'); // 解码 JSON 数据 $data = json_decode($json); ?>
此代码从请求体中读取原始 JSON 数据并进行解码 。
php://memory
和 php://temp
这两个包装器提供对内存或临时文件(当数据量超过一定阈值时,php://temp
会自动将数据写入临时文件)的读写访问 。它们常用于处理不需要持久化存储的临时数据,例如在数据处理管道中作为中间缓冲区 。
功能与用例:
php://memory
和 php://temp
用于在内存中或临时文件中存储和处理数据,适用于不需要持久化存储的场景 。
实战举例:
- 在内存中读写数据:
<?php $temp_stream = fopen('php://memory', 'r+'); fwrite($temp_stream, "Hello from memory!"); fseek($temp_stream, 0); // 将指针移回开头 echo fread($temp_stream, 1024); // 读取数据 fclose($temp_stream); ?>
此代码演示了如何在内存流中写入和读取数据。
data://
:数据嵌入
data://
包装器允许将小文件或数据直接以 Base64 编码或 URL 编码的形式嵌入到 URL 字符串中 。这常用于在 HTML 或 CSS 中嵌入图片、字体等小型资源,从而减少 HTTP 请求的数量,提高页面加载效率 。
功能与用例:
data://
用于将数据直接嵌入到 URL 字符串中,常用于在 HTML 或 CSS 中嵌入小型资源 。
实战举例:
- 打印嵌入的 Base64 编码数据:
<?php // 打印 "I love PHP" echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo='); ?>
此代码将 Base64 编码的字符串 “SSBsb3ZlIFBIUAo=” 解码并打印出 “I love PHP” 。
- 获取嵌入数据的媒体类型:
<?php $fp = fopen('data://text/plain;base64,', 'r'); $meta = stream_get_meta_data($fp); // 打印 "text/plain" echo $meta['mediatype']; ?>
此代码打开 data://
流并获取其媒体类型,输出 “text/plain” 。
- URL 编码的纯文本数据:
<?php $data = 'Günther says: 1+1 is 2, 10%40 is 20.'; $fp = fopen('data:text/plain,'.urlencode($data), 'rb'); echo stream_get_contents($fp); ?>
当传递纯字符串而非 Base64 编码时,需要进行 URL 编码以避免数据丢失 。
zip://
:ZIP 归档文件访问
zip://
包装器允许 PHP 函数直接访问 ZIP 压缩文件内部的特定文件,而无需先将整个归档文件解压到磁盘 。这对于处理压缩文件中的数据非常有用,例如,读取 OpenOffice 文档(本质上是 ZIP 文件)中的 XML 配置文件 。
功能与用例:
zip://
用于访问 ZIP 压缩文件内部的特定文件,无需解压整个归档文件 。
实战举例:
- 读取 ZIP 归档文件内的 XML 文件:
<?php $reader = new XMLReader(); // 访问 ZIP 文件 test.odt 内的 meta.xml 文件 $reader->open('zip://'. dirname(__FILE__). '/test.odt#meta.xml'); $odt_meta = array(); while ($reader->read()) { if ($reader->nodeType == XMLREADER::ELEMENT) { $elm = $reader->name; } else { if ($reader->nodeType == XMLREADER::END_ELEMENT && $reader->name == 'office:meta') { break; } if (!trim($reader->value)) { continue; } $odt_meta[$elm] = $reader->value; } } print_r($odt_meta); ?>
此代码使用 XMLReader
和 `zip://` 协议读取 `test.odt` 压缩包中的 `meta.xml` 文件内容 。
phar://
:PHP 归档文件访问
phar://
包装器用于访问 PHAR (PHP Archive) 文件。PHAR 是一种将完整的 PHP 应用程序或库打包成单个文件的格式,类似于 Java 的 JAR 文件,便于分发和部署 。它允许将多个 PHP 文件、图片、CSS 等资源打包在一起,并通过 phar://
协议像访问普通文件一样访问其中的内容 。
功能与用例:
phar://
用于访问 PHAR 归档文件内部的文件,类似于访问普通文件 。
实战举例:
- 访问 PHAR 归档文件内的文件:
<?php // 包含 PHAR 归档文件中的一个内部文件 include 'phar://coollibrary.phar/internal/file.php'; // 直接读取 PHAR 归档文件中的图片内容 header('Content-type: image/jpeg'); echo file_get_contents('phar:///fullpath/to/coollibrary.phar/images/wow.jpg'); ?>
此代码展示了如何使用 include
和 `file_get_contents` 函数访问 PHAR 归档文件中的 PHP 脚本和图片 。
expect://
:交互流处理
expect://
包装器用于处理交互流,使得 PHP 能够访问进程的标准输入、输出和错误流 。这是一个极其危险的包装器,通常在生产环境中被禁用 。
功能与用例:
expect://
用于执行系统命令,但由于其高风险性,通常不建议在生产环境中使用 。
实战举例:
- 执行系统命令:
<?php echo file_get_contents("expect://ls"); ?>
此代码尝试执行 ls
命令并输出结果 。
glob://
:路径名模式匹配
glob://
包装器用于匹配文件路径模式,允许遍历符合特定模式的文件 。
功能与用例:
glob://
用于查找匹配特定模式的文件路径,例如搜索目录并打印文件名和大小 。
实战举例:
- 遍历匹配模式的文件:
<?php foreach (glob("glob://*.txt") as $file) { echo file_get_contents($file); } ?>
此代码遍历当前目录下所有 .txt
文件并输出其内容 。
ftp://
:FTP 访问
ftp://
包装器用于访问 FTP 服务器,允许 PHP 函数读取和写入 FTP 服务器上的数据 。
功能与用例:
ftp://
用于从 FTP 服务器读取或写入数据,例如自动从外部 FTP 获取文件 。
实战举例:
- 从 FTP 服务器读取文件:
<?php // 假设 FTP 服务器地址为 ftp.example.com,用户名为 username,密码为 password $ftp = fopen("ftp://username:password@ftp.example.com/file.txt", "r"); if ($ftp) { echo stream_get_contents($ftp); fclose($ftp); } else { echo "Failed to open FTP stream."; } ?>
此代码尝试通过 FTP 协议连接到服务器并读取 file.txt
的内容 。