故事背景:又是一个激情四射的故事。前段时间咱们在弄咱们本身的开源基础组件,基础组件包括咱们常用的一些组件,好比说aliyunMQ,aliyunSearch、request(基于guzzle)等进行封装处理。就是这个request引起了一些美好的误会。javascript
老规矩,查看官方文档,全世界都会骗你,可是文档不会骗你。php
$HTTP_POST_VARS [已弃用] $_POST -- $HTTP_POST_VARS [已弃用] — HTTP POST 变量 当 HTTP POST 请求的 Content-Type 是 application/x-www-form-urlencoded 或 multipart/form-data 时,会将变量以关联数组形式传入当前脚本。 $HTTP_POST_VARS 包含相同的信息,但它不是一个超全局变量。 (注意 $HTTP_POST_VARS 和 $_POST 是不一样的变量,PHP 处理它们的方式不一样)
一看文档就知道所有信息了,$_POST支持的request中的header中的content-type的类型只有application/x-www-form-urlencoded 或 multipart/form-data 。css
当咱们使用guzzle的时候它会根据你传入的params是不是数组进行判断,若是不是数组会在body中。可是若是是数组它就会按照json方式进行传递,content-type会application/json的方式固然不会被$_POST进行处理。因此,这边是没有毛病的。可是,难道由于用了这个组件就不进行这个类型处理了吗?显然不行。html
php:// — 访问各个输入/输出流(I/O streams) PHP 提供了一些杂项输入/输出(IO)流,容许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及能够操做其余读取写入文件资源的过滤器。 php://input 是个能够访问请求的原始数据的只读流。 POST 请求的状况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,由于它不依赖于特定的 php.ini 指令。 并且,这样的状况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在须要更少的内存。 enctype="multipart/form-data" 的时候 php://input 是无效的。 Note: 在 PHP 5.6 以前 php://input 打开的数据流只能读取一次; 数据流不支持 seek 操做。 不过,依赖于 SAPI 的实现,请求体数据被保存的时候, 它能够打开另外一个 php://input 数据流并从新读取。 一般状况下,这种状况只是针对 POST 请求,而不是其余请求方式,好比 PUT 或者 PROPFIND。
这个东西说实话,就是$_POST基于这个进行封装处理了一层。它可以获取到最原始的数据,无论你是什么content-type,它都可以获取到数据。因此,当咱们的post的过来的数据是原始数据的时候,好比说是application/json或者' application/x-json,text/xml, application/xml,application/x-xml这些时候,$_POST都是没法获取到数据的。此刻,咱们就须要经过php://input进行获取原始数据了。可是,原始数据并非咱们想要的最终格式。所以,咱们须要进行封装一层。java
request类实际上是很好写的,可是通常的类中对post方式传递参数仍是老方式。所以,我改写了通常的类中获取post的参数,对于全部post请求方式的方法,针对不一样的content-type进行数据获取和原始数据的解析,弄成咱们想要的最终数组。
核心代码:json
public static function post($key = NULL, $default = NULL) { $data = []; if(in_array($_SERVER['CONTENT_TYPE'],self::$formats['json'])){ $data = file_get_contents('php://input'); $data = json_decode($data,true); } if(in_array($_SERVER['CONTENT_TYPE'],self::$formats['xml'])){ $data = file_get_contents('php://input'); $data = DataParser::toArray($data); } if($key==null && !empty($data)){ return $data; } if(!empty($data)){ return isset($data[$key]) ? $data[$key] : $default; } return static::lookup($_POST, $key, $default); }
在类中咱们会定义几个conten-type的format数组,经过$_SERVER['CONTENT_TYPE']来进行判断处理,针对性的进行数据获取和转换。数组
protected static $formats = array( 'html' => array('text/html', 'application/xhtml+xml'), 'txt' => array('text/plain'), 'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'), 'css' => array('text/css'), 'json' => array('application/json', 'application/x-json'), 'xml' => array('text/xml', 'application/xml', 'application/x-xml'), 'rdf' => array('application/rdf+xml'), 'atom' => array('application/atom+xml'), 'rss' => array('application/rss+xml'), );
针对xml格式的数据,同时封装了数据处理类app
public static function toArray($xml) { if (!$xml) { return false; } // 检查xml是否合法 $xml_parser = xml_parser_create(); if (!xml_parse($xml_parser, $xml, true)) { xml_parser_free($xml_parser); return false; } libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $data; }
就是简单的将xml格式数据转换成array数据。post
通常$_POST在不少项目中会有使用,基本上用来使用获取参数数据。一般的请求的content-type不会出现很奇怪的,可是我以为仍是须要本身去封装一层进行数据获取的类,可以省去不少麻烦,或者说对于大家项目的一致性有不少帮助。atom