PHP “php://input” vs $_POST

2022-08-30 06:03:42

我被指示使用该方法,而不是在与来自JQuery的Ajax请求交互时。我不明白的是,与 or 的全局方法相比,使用此方法的好处是什么。php://input$_POST$_POST$_GET


答案 1

原因是,无论内容类型如何,都会在请求的 HTTP 标头之后返回所有原始数据。php://input

PHP 超全局 ,只应该包装以下数据$_POST

  • application/x-www-form-urlencoded(简单表单帖子的标准内容类型)或
  • multipart/form-data(主要用于文件上传)

这是因为这些是用户代理必须支持的唯一内容类型。因此,服务器和PHP传统上不希望接收任何其他内容类型(这并不意味着它们不能)。

因此,如果您只是发布一个很好的旧HTML,则请求如下所示:form

POST /page.php HTTP/1.1

key1=value1&key2=value2&key3=value3

但是,如果您经常使用Ajax,这可能还包括使用类型(字符串,int,bool)和结构(数组,对象)交换更复杂的数据,因此在大多数情况下,JSON是最佳选择。但是,具有 JSON 有效负载的请求将如下所示:

POST /page.php HTTP/1.1

{"key1":"value1","key2":"value2","key3":"value3"}

内容现在是(或者至少没有上面提到的内容),所以PHP的-wrapper不知道如何处理它(还没有)。application/json$_POST

数据仍然存在,您只是无法通过包装器访问它。因此,您需要自己以原始格式获取它(只要它不是多部分/表单数据编码的)。file_get_contents('php://input')

这也是访问 XML 数据或任何其他非标准内容类型的方式。


答案 2

首先,关于PHP的基本事实。

PHP并不是为了明确地给你一个纯粹的REST(GET,POST,PUT,PATCH,DELETE)这样的接口来处理HTTP请求

但是,、 、 、 和超全局函数以及函数 filter_input_array() 对于普通人/外行人的需求非常有用。$_SERVER$_COOKIE$_POST$_GET$_FILES

(和)的头号隐藏优势是您的输入数据由PHP自动进行URL解码。您甚至从未考虑过必须这样做,特别是对于标准请求中的查询字符串参数或随请求提交的HTTP正文数据。$_POST$_GETGETPOST

其他 HTTP 请求方法

那些研究底层HTTP协议及其各种请求方法的人开始明白,有许多HTTP请求方法,包括经常引用的,(在Google的Apigee中未使用)和。PUTPATCHDELETE

在 PHP 中,没有超全局或输入筛选器函数,用于在不使用时获取 HTTP 请求正文数据。罗伊·菲尔丁的弟子们要做什么?;-)POST

但是,然后您将了解更多信息...

话虽如此,随着PHP编程知识的进步,并希望使用JavaScript的对象(对某些人来说是jQuery),你会看到这个方案的局限性。XmlHttpRequest

$_POST限制您在 HTTP 标头中使用两种媒体类型:Content-Type

  1. application/x-www-form-urlencoded
  2. multipart/form-data

因此,如果你想将数据值发送到服务器上的PHP,并让它显示在$_POST超全局中,那么你必须在客户端对它进行urlencode,并将所述数据作为键/值对发送 - 对于新手来说是一个不方便的步骤(特别是当试图弄清楚URL的不同部分是否需要不同形式的urlencoding时: 正常,原始等)。

对于所有jQuery用户,$.ajax()方法是在将JSON传输到服务器之前将其转换为URL编码的键/值对。您可以通过设置 processData:false 来覆盖此行为。只需阅读 $.ajax() 文档,不要忘记在 Content-Type 标头中发送正确的媒体类型。

php://input,但是...

即使您使用而不是HTTP请求正文数据,它也不会与HTTP一起使用 这是您想要允许文件上传时在HTML表单上使用的内容类型!php://input$_POSTPOSTContent-Typemultipart/form-data

<form enctype="multipart/form-data" accept-charset="utf-8" action="post">
    <input type="file" name="resume">
</form>

因此,在传统的PHP中,要处理来自HTTP请求的多种内容类型,您将学习使用或,,和。在 PHP 中,没有办法只对 HTTP 请求使用一个通用输入源。POST$_POSTfilter_input_array(POST)$_FILESphp://inputPOST

您无法通过 、 或 获取文件,也无法在 或 中获取 JSON/XML/YAML。$_POSTfilter_input_array(POST)php://inputfilter_input_array(POST)$_POST

PHP 手册: php://input

php://input 是一个只读流,允许您从请求正文中读取原始数据...php://input 不适用于 enctype=“multipart/form-data”。

PHP框架来拯救?

像Codeigniter 4和Laravel这样的PHP框架使用外观来为上述内容提供更清晰的接口(或对象)。这就是为什么专业的PHP开发人员使用框架而不是原始PHP的原因。IncomingRequestRequest

当然,如果你喜欢编程,你可以设计自己的门面对象来提供框架的作用。正是因为我花时间调查了这个问题,我才能够写出这个答案。

网址编码?这到底是怎么回事!!!???

通常,如果您使用 HTML 表单执行正常的同步(当整个页面重绘时)HTTP 请求,则用户代理(Web 浏览器)将为您对表单数据进行 url 编码。如果要使用该对象执行异步 HTTP 请求,则必须设置 urlencoded 字符串并发送它,如果希望该数据显示在 $_POST 超全局中XmlHttpRequest

你与JavaScript的联系如何?:-)

从 JavaScript 数组或对象转换为 urlencoded 字符串会困扰许多开发人员(即使使用新的 API,如 Form Data)。他们宁愿只能够发送JSON,并且客户端代码这样做会更有效率。

请记住(眨眼,眨眼),普通的Web开发人员不会像你和我一样学习直接使用对象,全局函数,字符串函数,数组函数和正则表达式;-)。对他们来说,Urlencoding是一场噩梦。;-)XmlHttpRequest

PHP,什么原因?

PHP缺乏直观的XML和JSON处理,这让很多人望而却步。你可能会认为它现在已经是PHP的一部分(叹息)。

如此多的媒体类型(过去的MIME类型)

XML,JSON和YAML都有可以放入HTTP标头中的媒体类型。Content-Type

  • application/xml
  • application/json
  • application/yaml (尽管 IANA 没有列出官方名称)

查看 IANA 定义了多少媒体类型(以前称为 MIME 类型)。

看看有多少个HTTP标头

php://input 或胸围

使用 php://input 流可以规避 PHP 强加给世界的婴儿看护/手持抽象级别。:-)权力越大,责任越大!

现在,在处理流经的数据值之前,您应该/必须做一些事情。php://input

  1. 确定是否指示了正确的 HTTP 方法(GET、POST、PUT、PATCH、DELETE 等)
  2. 确定是否已传输 HTTP 内容类型标头。
  3. 确定内容类型的是否为所需的媒体类型。
  4. 确定发送的数据是否为格式正确的 XML / JSON / YAML / 等。
  5. 如有必要,将数据转换为 PHP 数据类型:数组或对象。
  6. 如果这些基本检查或转换中的任何一个失败,请引发异常

字符编码呢?

啊,哈!是的,您可能希望发送到应用程序中的数据流采用 UTF-8 编码,但您如何知道它是否是 UTF-8 编码?

两个关键问题。

  1. 您不知道有多少数据是通过 。php://input
  2. 您不确定数据流的当前编码。

您是否打算在不知道首先有多少数据的情况下尝试处理流数据?这是一个可怕的想法。您不能完全依赖 HTTP 标头来获取有关流输入大小的指导,因为它可能是欺骗性的。Content-Length

您将需要一个:

  1. 流大小检测算法。
  2. 应用程序定义的流大小限制(Apache / Nginx / PHP限制可能太宽泛)。

您是否打算在不知道流的当前编码的情况下尝试将流数据转换为 UTF-8?如何?iconv 流过滤器(iconv 流过滤器示例)似乎需要一个开始和结束编码,就像这样。

'convert.iconv.ISO-8859-1/UTF-8'

因此,如果您尽职尽责,您将需要:

  1. 流编码检测算法。
  2. 动态/运行时流过滤器定义算法(因为您无法先验地知道开始编码)。

(更新:将强制所有内容都设置为UTF-8,但您仍然必须考虑iconv库可能不知道如何翻译的字符。换句话说,您必须如何定义当字符无法翻译时要执行的操作:1)插入虚拟字符,2)失败/抛出和异常)。'convert.iconv.UTF-8/UTF-8'

您不能完全依赖 HTTP 标头,因为这可能表示类似压缩的内容,如下所示。这不是你想在iconv上做出决定的。Content-Encoding

Content-Encoding: gzip

因此,一般步骤可能是...

第一部分:HTTP请求相关

  1. 确定是否指示了正确的 HTTP 方法(GET、POST、PUT、PATCH、DELETE 等)
  2. 确定是否已传输 HTTP 内容类型标头。
  3. 确定内容类型的是否为所需的媒体类型。

第二部分:流数据相关

  1. 确定输入流的大小(可选,但建议使用)。
  2. 确定输入流的编码。
  3. 如有必要,将输入流转换为所需的字符编码 (UTF-8)。
  4. 如有必要,请撤消任何应用程序级别的压缩或加密,然后重复步骤 4、5 和 6。

第 III 部分:数据类型相关

  1. 确定发送的数据是否格式正确的XML / JSON / YMAL / 等。

(请记住,数据仍然可以是URL编码的字符串,然后您必须对其进行解析和URL解码)。

  1. 如有必要,将数据转换为 PHP 数据类型:数组或对象。

第 IV 部分:数据值相关

  1. 筛选输入数据。

  2. 验证输入数据。

现在你看到了吗?

超全局,以及php.ini输入限制设置,对于外行人来说更简单。但是,在使用流时,处理字符编码更加直观和高效,因为不需要遍历超全局(或数组,通常)来检查输入值的正确编码。$_POST


推荐