PHP"php:// input"vs $ _POST

Lee*_*Lee 221 php ajax input

我被指示使用该方法php://input而不是$_POST与来自JQuery的Ajax请求交互时.我不明白的是使用这个VS的全局法的优点$_POST$_GET.

Qua*_*unk 437

原因是php://input返回请求的HTTP标头之后的所有原始数据,而不管内容类型如何.

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
Run Code Online (Sandbox Code Playgroud)

但是如果你正在使用Ajax,那么这个probaby还包括用类型(string,int,bool)和结构(数组,对象)交换更复杂的数据,所以在大多数情况下JSON是最好的选择.但是带有JSON-payload的请求看起来像这样:

POST /page.php HTTP/1.1

{"key1":"value1","key2":"value2","key3":"value3"}
Run Code Online (Sandbox Code Playgroud)

现在内容将是application/json(或者至少没有上述内容),因此PHP的$_POST-wrapper不知道如何处理(尚未).

数据仍然存在,您无法通过包装器访问它.所以你需要自己以原始格式获取它file_get_contents('php://input')(只要它不是multipart/form-data-encoded).

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

  • 为"这也是您访问XML数据或任何其他非标准内容类型的方式"+1 (38认同)

Ant*_*dge 55

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

PHP 的设计目的不是明确地为您提供一个纯 REST(GET、POST、PUT、PATCH、DELETE)之类的接口来处理 HTTP 请求

然而,$_SERVER$_COOKIE$_POST$_GET,和$_FILES 超全局变量和函数filter_input_array()是一般人的/外行的需求是非常有用的。

$_POST(and $_GET)的第一个隐藏优势是您的输入数据由 PHP 自动进行 url 解码。您甚至从未想过必须这样做,尤其是对于标准GET请求中的查询字符串参数或随POST请求提交的 HTTP 正文数据。

其他 HTTP 请求方法

那些研究底层 HTTP 协议及其各种请求方法的人会了解到,有许多 HTTP 请求方法,包括经常被引用的PUTPATCH(在 Google 的 Apigee 中未使用)和DELETE

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

然而,然后你会学到更多......

话虽如此,随着您在 PHP 编程知识方面的进步并想要使用 JavaScript 的XmlHttpRequest对象(对于某些人为 jQuery),您会看到这种方案的局限性。

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

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

因此,如果您想将数据值发送到服务器上的 PHP,并将其显示在$_POSTsuperglobal 中,那么您必须在客户端对其进行urlencode并将所述数据作为键/值对发送——这对新手来说是一个不方便的步骤(尤其是在尝试确定 URL 的不同部分是否需要不同形式的 urlencoding:正常、原始等时......)。

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

php://输入,但是...

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

<form enctype="multipart/form-data" accept-charset="utf-8" action="post">
    <input type="file" name="resume">
</form>
Run Code Online (Sandbox Code Playgroud)

因此,在传统的PHP,要处理的内容类型从HTTP多样性POST的要求,您将学习如何使用$_POSTfilter_input_array(POST)$_FILESphp://input。无法POST在 PHP 中为 HTTP请求只使用一个通用输入源。

您无法通过$_POST、filter_input_array(POST) 或获取文件php://input,并且无法在filter_input_array(POST)或 中获取 JSON/XML/YAML $_POST

PHP 手册:php://input

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

PHP 框架来拯救?

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

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

网址编码?有没有搞错!!!???

通常,如果您使用 HTML 表单执行正常的同步(当整个页面重绘时)HTTP 请求,则用户代理(Web 浏览器)将为您对表单数据进行 urlencode。如果您想使用该XmlHttpRequest对象执行异步 HTTP 请求,那么您必须构造一个 urlencoded 字符串并发送它,如果您希望该数据显示在$_POSTsuperglobal 中

你对 JavaScript 的了解如何?:-)

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

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

PHP,什么给?

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

这么多媒体类型(过去的 MIME 类型)

XML、JSON 和 YAML 都有可以放入 HTTPContent-Type标头的媒体类型。

  • 应用程序/xml
  • 应用程序/json
  • application/yaml(虽然 IANA 没有列出官方名称)

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

看看有多少HTTP 标头

php://input 或 bust

使用php://input流允许您绕过 PHP 强加给世界的婴儿看护/手持抽象级别。:-) 拥有权利的同时也被赋予了重大的责任!

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

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

字符编码呢?

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

两个关键问题。

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

您是否打算在不知道流数据的情况下尝试处理流数据?这是一个可怕的想法。您不能完全依赖 HTTPContent-Length标头来指导流输入的大小,因为它可能被欺骗。

你将需要一个:

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

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

'convert.iconv.ISO-8859-1/UTF-8'
Run Code Online (Sandbox Code Playgroud)

因此,如果您有良心,您将需要:

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

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

您不能完全依赖 HTTPContent-Encoding标头,因为这可能表示如下所示的压缩。这不是您想要就 iconv 做出决定的原因。

Content-Encoding: gzip
Run Code Online (Sandbox Code Playgroud)

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

第一部分:HTTP 请求相关

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

第二部分:流数据相关

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

第三部分:数据类型相关

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

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

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

第四部分:数据价值相关

  1. 过滤输入数据。

  2. 验证输入数据。

现在你明白了吗?

$_POST超全局,与输入范围的php.ini设置一起,是外行简单。然而,在使用流时处理字符编码更加直观和有效,因为不需要循环遍历超全局变量(或数组,通常)来检查输入值是否正确编码。

  • 哦哇!这个答案应该有更高的评价。非常感谢您为黑暗带来泛光灯。 (6认同)

Rob*_*gar 50

php://input可以为您提供数据的原始字节.如果POSTed数据是JSON编码结构(通常是AJAX POST请求的情况),这将非常有用.

这是一个功能:

  /**
   * Returns the JSON encoded POST data, if any, as an object.
   * 
   * @return Object|null
   */
  private function retrieveJsonPostData()
  {
    // get the raw POST data
    $rawData = file_get_contents("php://input");

    // this returns null if not valid json
    return json_decode($rawData);
  }
Run Code Online (Sandbox Code Playgroud)

$_POST当您从传统POST提交的表单处理键值数据时,该数组更有用.这仅适用于POSTed数据采用可识别格式的情况(通常application/x-www-form-urlencoded请参阅http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4).

  • 值得注意的是,如果将`true`作为第二个参数传递给`json_decode`,它将返回一个关联数组. (7认同)

Nam*_*ess 24

如果发布数据格式错误,$ _POST将不包含任何内容.然而,php://输入将具有格式错误的字符串.

例如,有一些ajax应用程序,它们不能形成用于上传文件的正确的后键值序列,只是将所有文件作为发布数据转储,没有变量名称或任何东西.$ _POST将为空,$ _FILES也为空,而php://输入将包含精确文件,写为字符串.