2024 年 PHP 日本大会

支持的协议和封装器

PHP 带有很多内置的封装器,用于各种 URL 风格的协议,可与文件系统函数一起使用,例如 fopen()copy()file_exists()filesize()。除了这些封装器之外,还可以使用 stream_wrapper_register() 函数注册自定义封装器。

注意 用于描述封装器的 URL 语法仅支持 scheme://... 语法。不支持 scheme:/scheme: 语法。

目录

添加注释

用户贡献的注释 31 条注释

24
fabacrans__ at __nospamhotmail__ dot __com
11 年前
您可以使用“php://input”来接受和解析“PUT”、“DELETE”等请求。

<?php
// 解析“PUT”请求的示例
parse_str(file_get_contents('php://input'), $_PUT);

// 结果
print_r($_PUT);
?>

(对 Restful API 非常有用)
17
ben dot johansen at gmail dot com
18 年前
如何使用 php://input 获取原始 POST 数据的示例

// 读取原始数据
$roughHTTPPOST = file_get_contents("php://input");
// 将其解析为变量
parse_str($roughHTTPPOST);

如果您执行 readfile("php://input"),您将获得 POST 数据的长度
13
aidan at php dot net
20 年前
常量

* STDIN
* STDOUT
* STDERR

在 PHP 4.3.0 中引入,与 fopen('php://stdx') 结果资源同义。
18
sander at medicore dot nl
17 年前
要创建一个原始 tcp 监听器系统,我使用以下方法

xinetd 守护进程,配置如下
服务测试
{
disable = no
type = UNLISTED
socket_type = stream
protocol = tcp
bind = 127.0.0.1
port = 12345
wait = no
user = apache
group = apache
instances = 10
server = /usr/local/bin/php
server_args = -n [您的 php 文件]
only_from = 127.0.0.1 #必须注意安全性#
log_type = FILE /var/log/phperrors.log
log_on_success += DURATION
}

现在使用 fgets(STDIN) 读取输入。创建连接非常快,运行良好。写入可以使用 STDOUT 完成,或者只是 echo。请注意,您完全绕过了 Web 服务器,因此某些变量将不可用。
13
ben dot johansen at gmail dot com
18 年前
在尝试使用 PHP 和 Javascript 进行 AJAX 时,我遇到一个问题,即无法使用 $_REQUEST 或 $_POST 在 PHP 5 中读取以下 javascript 中的 POST 参数。我最终找到了如何使用 php://input 指令读取原始数据的方法。

Javascript 代码
=============
// 创建请求实例
xhttp = new XMLHttpRequest();
// 设置事件处理程序
xhttp.onreadystatechange = serviceReturn;
// 准备调用,http 方法=POST,true=异步调用
var Args = 'number='+NbrValue;
xhttp.open("POST", "http://<?php echo $_SERVER['SERVER_NAME'] ?>/webservices/ws_service.php", true);
// 使用参数发送调用
xhttp.send(Args);

PHP 代码
// 读取原始数据
$roughHTTPPOST = file_get_contents("php://input");
// 将其解析为变量
parse_str($roughHTTPPOST);
11
php at rapsys dot eu
12 年前
这是一个读取压缩原始 POST 数据而无需启用全局变量的代码片段。

我需要它来读取 ocs 代理提交的 xml POST 数据。数据以 Content-Type: application/x-compressed(zlib 压缩数据)发送。

它似乎与一个仍然似乎已损坏的旧错误有关
https://bugs.php.net/bug.php?id=49411

重要的部分是将默认窗口设置为 15 而不是 -15。

代码片段
<?php
$data
= '';
$fh = fopen('php://input', 'rb');
stream_filter_append($fh, 'zlib.inflate', STREAM_FILTER_READ, array('window'=>15));
while(!
feof($fh)) {
$data .= fread($fh, 8192);
}
?>
10
sebastian dot krebs at kingcrunch dot de
13 年前
流 php://temp/maxmemory:$limit 将数据存储在内存中,除非达到限制。然后它会将整个内容写入临时文件并释放内存。我没有找到一种方法可以至少将部分数据返回到内存。
12
Hayley Watson
6 年前
尽管名称相同,您可以同时打开多个 //memory 或 //temp 流;每次使用 fopen() 打开此类流时,都会打开一个新的流,与其他流无关。

创建此类流时,您不会在路径中添加任何唯一标识符,这一点暗示了这一点,但没有明确说明。

<?php

$hello
= fopen('php://memory', 'r+'); // $hello, $php, $world 都是不同的流。
$php = fopen('php://memory', 'r+');
$world = fopen('php://memory', 'r+'); // 它们不是同一个流被打开三次。

fputs($hello, "Hello ");
fputs($php, "PHP ");
rewind($php);
fputs($world, "World!");
rewind($hello);
rewind($world);

echo
'[', stream_get_contents($hello), '][', stream_get_contents($php), '][', stream_get_contents($world), ']';
// 如果它们是同一个流,输出将是 "[World!][World!][World!]".
?>
12
gjaman at gmail dot com
16年前
您可以通过组合包装器来解压缩 (gzip) 输入流

例如:$x = file_get_contents("compress.zlib://php://input");

我使用此方法解压缩推送到我的 Web 服务器的 gzip 流
9
heitorsiller at uol dot com dot br
18 年前
对于读取 XML 流,这将非常有效
<?php

$arq
= file_get_contents('php://input');

?>

然后您可以像这样解析 XML

<?php

$xml
= xml_parser_create();

xml_parse_into_struct($xml, $arq, $vs);

xml_parser_free($xml);

$data = "";

foreach(
$vs as $v){

if(
$v['level'] == 3 && $v['type'] == 'complete')
$data .= "\n".$v['tag']." -> ".$v['value'];
}

echo
$data;

?>

附注:这对于接收来自手机公司的移动来源 (MO) 短信消息特别有用。
8
nargy at yahoo dot com
20 年前
以追加模式打开 php://output 时会出错,正确的做法是
$fp=fopen("php://output","w");
fwrite($fp,"Hello, world !<BR>\n");
fclose($fp);
6
vibhavsinha91 at gmail dot com
10年前
写入错误流时,error_log() 函数是写入 php://stderr 的简写。此函数还允许在通过 Apache 等 Web 服务器运行时写入 Web 服务器日志。
4
匿名用户
6 年前
预先警告

file_get_contents 中使用的 file:// 协议用作“任何无法识别的协议”的默认值。因此

aldfjadlfadfladfl://whatever

将提供与以下相同的输出:

file://whatever
7
匿名用户
7年前
如果要通过 php://input 过滤传入数据,请使用以下代码:

file_get_contents("php://filter/read=string.strip_tags/resource=php://input");

我找不到任何解释如何执行此操作的文档。我遇到的所有示例都建议必须使用完整且实际的 URL(这对我不起作用)。

不过,这似乎有效。
6
Justin Megawarne
11 年前
如果我对实现代码的理解正确,那么每次打开 php://memory 流时,都会获得新的存储分配。也就是说,php://memory 不是共享内存。
7
sam at bigwig dot net
21年前
[编辑注:有一种方法可以知道。所有响应标头(来自最终响应服务器和中间重定向器)都可以在 $http_response_header 或 stream_get_meta_data() 中找到,如上所述。]

如果您打开一个 HTTP URL 并且服务器发出 Location 样式的重定向,则将读取重定向的内容,但您无法知道发生了这种情况。

因此,如果您随后解析返回的 html 并尝试使相对 URL 合理化,您可能会出错。
5
chris at free-source dot com
19年前
如果您正在寻找基于 unix 的 smb 包装器,则没有内置的包装器,但我使用 http://www.zevils.com/cgi-bin/viewcvs.cgi/libsmbclient-php/ (最后的 tarball 链接)很幸运。
5
jerry at gii dot co dot jp
17 年前
STDIN、STDOUT 和 STDERR 不仅仅允许用于 CLI 程序,而且不允许用于从 STDIN 读取的程序。如果您尝试输入一个简单的测试程序,这可能会让您感到困惑。
5
lupti at yahoo dot com
21年前
我发现使用 file_get_contents 与 php://input 非常方便且高效。以下是代码

$request = "";
$request = file_get_contents("php://input");

我不需要将 URL 文件字符串声明为“r”。它会自动处理以读取模式打开文件。

然后,我可以将此 $request 字符串用作 XML 解析器的數據。
5
aaron dot mason+php at thats-too-much dot info
12 年前
注意代码注入,各位——就像您从用户那里获取的任何其他内容一样,首先对其进行清理。这一点怎么强调都不为过——如果我有一美元用于每次看到代码从表单中获取输入并直接使用(我自己也做过,我也很愚蠢),我可能就拥有了 PHP。虽然在 URL 包装器中使用来自表单的数据是在自找麻烦,但您可以通过确保输入正常且不太可能为 LulzSec 等人造成破坏提供机会来最大限度地减少麻烦。
5
leonid at shagabutdinov dot com
13 年前
对于 Windows 的 https,请启用此扩展

extension=php_openssl.dll
4
nyvsld at gmail dot com
19年前
php://stdin 支持 fseek() 和 fstat() 函数调用,
而 php://input 不支持。
4
ben dot johansen at gmail dot com
18 年前
后续

我发现如果我在 AJAX 调用中添加此行,则值将显示在 $_POST 中

xhttp.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
1
kazdotkanso at geeemail dot com
4年前
php://fd/ 包装器仅在 cli 工具中受支持。
3
oliver at codeinline dot com
10年前
处理大型文件上传的一种有用方法是执行以下操作:

copy(("php://input"),$tmpfile);

因为这避免了仅为了缓冲文件内容而使用大量内存。

此处的正确 mime 类型应该是“application/octet-stream”,但是如果您在 POST 上设置此类型或任何其他已识别的 mime 类型(而不是“multipart/form-data”),则 $HTTP_RAW_POST_DATA 将被填充,并且内存也会被消耗。

将 mime 类型设置为“multipart/form-data”会引发“PHP 警告:未知行 0 中 multipart/form-data POST 数据中缺少边界”,但它似乎可以正常工作。
3
匿名用户
12 年前
对于 php://filter,/resource=foo 部分必须放在最后。foo 完全不需要转义。
php://filter/resource=foo/read=somefilter 将尝试打开文件 'foo/read=somefilter',而 php://filter/read=somefilter/resource=foo 将使用 somefilter 过滤器打开文件 'foo'。
3
dave at 4mation dot com dot au
11 年前
使用 php://temp/maxmemory 作为流会占用脚本的内存;使用这种类型的流不会指定新的内存池。
但是,正如文档中所述,当超过指定的 maxmemory 限制后,此流类型将开始写入文件。内存限制不会监控此文件缓冲区。
如果您希望脚本具有合理的较小内存限制(例如 32MB),但仍然能够处理大量流数据(例如 256MB),则此功能非常有用。

只有在使用诸如 fputs() 之类的流函数时才有效;如果您使用 $buffer .= 'string'; 或 $buffer = $buffer . 'string';,则会将流数据调回到 PHP 中,这将达到限制。

作为一个实际示例

<?php
// 0.5MB 内存限制
ini_set('memory_limit', '0.5M');
// 2MB 流限制
$buffer = fopen('php://temp/maxmemory:1048576', 'r+');
$x = 0;
// 尝试将 1MB 写入流
while ($x < 1*1024*1024) {
fputs($buffer, 'a');
$x++;
}
echo
"这将永远不会显示";
?>

但是,将 fopen 更改为使用 php://temp/maxmemory:1(一个字节,而不是一百万字节),它将立即开始写入无限文件流,从而避免内存限制错误。
1
匿名用户
8年前
请注意,STDIN 等仅在 CLI 中定义。
1
ohcc at 163 dot com
9年前
<?php
//必要时启用 $HTTP_RAW_POST_DATA
ini_set('always_populate_raw_post_data',-1);
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
echo
$HTTP_RAW_POST_DATA;
?>
1
匿名用户
11 年前
在 PHP 5.4+ 中,如果将 enable_post_data_reading 设置为 Off,则可以通过 php://input 读取多部分数据。

当然,如果将其设置为 off,则 $_POST 和 $_FILES 超全局变量将根本不会填充。现在完全由您来解析数据。
-2
nguyenanthuan at gmail dot com
10年前
指向 php://memory 和 php://temp 的每个流指针都有其自己的内存分配,因此您可以打开多个流指针来存储您分离的值。

<?php
$fp
= fopen("php://temp", "r+");
$fp2 = fopen("php://temp", "r+");

fwrite($fp, "line1\n");
fwrite($fp2, "line4\n");
fwrite($fp, "line2\n");
fwrite($fp2, "line5\n");
fwrite($fp, "line3\n");
fwrite($fp2, "line6\n");

var_dump(memory_get_usage());

rewind($fp);
while(!
feof($fp)) {
var_dump(fread($fp, 1024));
}
fclose($fp);
var_dump(memory_get_usage());

rewind($fp2);
while(!
feof($fp2)) {
var_dump(fread($fp2, 1024));
}
fclose($fp2);
var_dump(memory_get_usage());
?>

关闭它们的流句柄也将释放已分配的内存。

php://memory 流类型为 MEMORY,而 php://temp 流类型为 STDIO FILE*。
To Top