是否可以在开始阅读之前知道php:// input是否包含数据?

时间:2012-07-02 18:08:56

标签: php http

根据documentationphp://input并不总是包含HTTP请求正文。

我有一些代码在脚本启动时始终打开流,以使其可供用户应用程序使用:

$stream = fopen('php://input', 'rb');

如果用户应用程序尝试从空流中读取,则在Content-Length > 0时,我希望我的库引发异常:

  

请求正文无法使用。

我的问题是:

  • 如果流为空,feof()会返回false,而fread()尚未被调用;
  • 我不能fread() 1个字节,然后fseek(),因为此流不支持搜索;
  • 我无法打开另一个php://input并尝试事先阅读,因为我们不能依赖此流可用多次;
  • 出于性能原因,我不想盲目地将php://input复制到php://temp,然后再将手提交给用户应用程序。

因此,是否可以判断php://input是否在fopen()之后,但在任何fread() 之前包含数据?

2 个答案:

答案 0 :(得分:1)

我找到的解决方案是创建一个表示请求正文的类,并直接从此类而不是php://input读取:

class RequestBody
{
    protected $firstByte;

    protected $isEmpty;

    public function __construct($stream)
    {
        $this->firstByte = fread($stream, 1);
        $this->isEmpty = ($this->firstByte === '');

        // ...
    }

    public function isEmpty()
    {
        return $this->isEmpty;
    }

    public function read($length)
    {
        // ...
    }
}

$body = new RequestBody(fopen('php://input', 'rb'));

类构造函数读取流的第一个字节,将其存储供以后使用,并立即知道流是否为空。

read()通过在第一次调用时返回第一个字节+ $length - 1字节来隐藏这种复杂性。

答案 1 :(得分:0)

  

“使用php://输入打开的流只能读取一次;流不支持搜索操作。”

http://php.net/manual/en/wrappers.php.php

对我而言,这表明它是一种老式的只读流。你不能寻找和测试它是文件的结尾还是长度。