一般接收 POST 资料都是使用 $_POST 这个变量,
但 $_POST 只能取得 Content-type 為 application/x-www-form-urlencoded 或 multipart/form-data 的資料。
當 Content-type 為 text/xml 等其他類型的資料,$_POST便無法取得。
若有接收其他類型 Content-type 的需求,可以使用 php://input,
php://input 可以讀取 request body 的資料,所以可以取得 HTTP POST 的資料,
但有一個限制,就是當 Content-type 為 multipart/form-data ,php://input 會取得空值,無法使用。
下面範例 php://input 搭配 file_get_contents 使用,和 $_POST 比較在 Content-type 分別為 multipart/form-data、application/x-www-form-urlencoded、text/xml 時,兩者接收資料的情況
接收資料的程式:
後面範例用來 request 的網址:http://127.0.0.1/test/test.php
範例 1:(multipart/form-data )
使用 curl 模擬 HTTP POST,Content-type 為 multipart/form-data
(CURLOPT_POSTFIELDS 資料為陣列時,會以 multipart/form-data 方式傳送)
輸出結果:file_get_contents("php://input",'r') 取不到 multipart/form-data 的值
$postdata:string(0) ""
$_POST (OK):array(2) { ["aa"]=> string(3) "123" ["bb"]=> string(3) "456" }
範例 2:(application/x-www-form-urlencoded )
使用 curl 模擬 HTTP POST,Content-type 為 application/x-www-form-urlencoded
輸出結果:file_get_contents("php://input",'r') 和 $_POST 的資料一樣,但 $_POST 已轉成陣列
$postdata (OK):string(13) "aa=123&bb=456"
$_POST (OK):array(2) { ["aa"]=> string(3) "123" ["bb"]=> string(3) "456" }
範例 3:(text/xml )
使用 curl 模擬 HTTP POST,Content-type 為 text/xml
輸出結果:file_get_contents("php://input",'r') 可以讀取 POST 過來的 XML 資料,$_POST 無法讀取
$postdata (OK):string(36) "<?xml version="1.0" encoding="utf-8"?><root><aa>123</aa><bb>456</bb></root>"
$_POST:array(0) {}
結論:
所以如果有一 PHP 程式,用來接收其它地方 POST 過來的資料,例如是 XML 的資料,應該就可以利用 file_get_contents("php://input",'r') 來取得 POST 過來的內容。
當 Content-type 為 text/xml 等其他類型的資料,$_POST便無法取得。
若有接收其他類型 Content-type 的需求,可以使用 php://input,
php://input 可以讀取 request body 的資料,所以可以取得 HTTP POST 的資料,
但有一個限制,就是當 Content-type 為 multipart/form-data ,php://input 會取得空值,無法使用。
下面範例 php://input 搭配 file_get_contents 使用,和 $_POST 比較在 Content-type 分別為 multipart/form-data、application/x-www-form-urlencoded、text/xml 時,兩者接收資料的情況
接收資料的程式:
後面範例用來 request 的網址:http://127.0.0.1/test/test.php
1
2
3
|
$postdata
=
file_get_contents
(
"php://input"
,
'r'
);
var_dump(
$postdata
);
// php://input
var_dump(
$_POST
);
|
範例 1:(multipart/form-data )
使用 curl 模擬 HTTP POST,Content-type 為 multipart/form-data
(CURLOPT_POSTFIELDS 資料為陣列時,會以 multipart/form-data 方式傳送)
1
2
3
4
5
6
7
8
|
$ch
= curl_init();
$data
=
array
(
'aa'
=>
'123'
,
'bb'
=>
'456'
);
curl_setopt(
$ch
, CURLOPT_URL,
'http://127.0.0.1/test/test.php'
);
curl_setopt(
$ch
, CURLOPT_POST, 1);
curl_setopt(
$ch
, CURLOPT_POSTFIELDS,
$data
);
curl_setopt(
$ch
, CURLOPT_HEADER,0);
curl_exec(
$ch
);
curl_close(
$ch
);
|
$postdata:string(0) ""
$_POST (OK):array(2) { ["aa"]=> string(3) "123" ["bb"]=> string(3) "456" }
範例 2:(application/x-www-form-urlencoded )
使用 curl 模擬 HTTP POST,Content-type 為 application/x-www-form-urlencoded
1
2
3
4
5
6
7
8
9
|
$ch
= curl_init();
$data
=
'aa=123&bb=456'
;
curl_setopt(
$ch
, CURLOPT_URL,
'http://127.0.0.1/test/test.php'
);
curl_setopt(
$ch
, CURLOPT_HTTPHEADER,
array
(
"Content-type: application/x-www-form-urlencoded"
));
curl_setopt(
$ch
, CURLOPT_POST, 1);
curl_setopt(
$ch
, CURLOPT_POSTFIELDS,
$data
);
curl_setopt(
$ch
, CURLOPT_HEADER,0);
curl_exec(
$ch
);
curl_close(
$ch
);
|
$postdata (OK):string(13) "aa=123&bb=456"
$_POST (OK):array(2) { ["aa"]=> string(3) "123" ["bb"]=> string(3) "456" }
範例 3:(text/xml )
使用 curl 模擬 HTTP POST,Content-type 為 text/xml
1
2
3
4
5
6
7
8
9
|
$ch
= curl_init();
$data
=
'<?xml version="1.0" encoding="utf-8"?><root><aa>123</aa><bb>456</bb></root>'
;
curl_setopt(
$ch
, CURLOPT_URL,
'http://127.0.0.1/test/test.php'
);
curl_setopt(
$ch
, CURLOPT_HTTPHEADER,
array
(
"Content-type: text/xml;charset=\"utf-8\""
));
curl_setopt(
$ch
, CURLOPT_POST, 1);
curl_setopt(
$ch
, CURLOPT_POSTFIELDS,
$data
);
curl_setopt(
$ch
, CURLOPT_HEADER,0);
curl_exec(
$ch
);
curl_close(
$ch
);
|
$postdata (OK):string(36) "<?xml version="1.0" encoding="utf-8"?><root><aa>123</aa><bb>456</bb></root>"
$_POST:array(0) {}
結論:
所以如果有一 PHP 程式,用來接收其它地方 POST 過來的資料,例如是 XML 的資料,應該就可以利用 file_get_contents("php://input",'r') 來取得 POST 過來的內容。
PHP将XML转换成数组
做接口开发的时候经常会碰到别人提交给你的是xml格式的数据,常见的微信接口、支付宝接口等,他们的接口如发送消息通信都是xml格式的,那么我们先想办法拿到这个xml数据,然后再将其转化成数组。
假设我们获取到一个这样的XML:
<root> <user>月光光abcd</user> <pvs>13002</pvs> <ips> <baidu_ip>1200</baidu_ip> <google_ip>1829</google_ip> </ips> <date>2016-06-01</date> </root>
通过simplexml_load_string()解析读取xml数据,然后先转成json格式,再转换成数组。
function xmlToArray($xml){ //禁止引用外部xml实体 libxml_disable_entity_loader(true); $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); $val = json_decode(json_encode($xmlstring),true); return $val; }
也可以
调用xmlToArray()可得到以下结果:
得到数组后,我们就可以对数据进行各种处理了。
语法
PHP的语法simplexml_load_string()函数具有以下语法。
simplexml_load_string(data,classname,options,ns,is_prefix);
参数
参数 | 是必须的 | 描述 |
---|---|---|
数据 | 需要。 | 一个格式正确的XML字符串 |
班级名称 | 可选的。 | 新对象的类 |
选项 | 可选的。 | 额外的Libxml参数。通过指定选项和1或0(TRUE或FALSE,例如LIBXML_NOBLANKS(1))来设置 |
ns | 可选的。 | 命名空间前缀或URI |
is_prefix | 可选的。 | 如果ns是前缀,则为TRUE。如果ns是URI,则为FALSE。默认值为FALSE |
选项的可能值:
- LIBXML_COMPACT - 激活节点分配优化(可加速应用程序)
- LIBXML_DTDATTR - 设置默认DTD属性
- LIBXML_DTDLOAD - 加载外部子集
- LIBXML_DTDVALID - 使用DTD进行验证
- LIBXML_NOBLANKS - 删除空白节点
- LIBXML_NOCDATA - 将CDATA合并为文本节点
- LIBXML_NOEMPTYTAG - 展开空标记(例如对<br> </ br>),仅在DOMDocument-> save()和DOMDocument-> saveXML()函数中可用
- LIBXML_NOENT - 替代实体
- LIBXML_NOERROR - 不显示错误报告
- LIBXML_NONET - 加载文档时禁用网络访问
- LIBXML_NOWARNING - 不显示警告报告
- LIBXML_NOXMLDECL - 保存文档时删除XML声明
- LIBXML_NSCLEAN - 删除多余的命名空间声明
- LIBXML_PARSEHUGE - 设置XML_PARSE_HUGE标志,放宽解析器的任何硬编码限制。这会影响极限,如文档的最大深度和文本节点大小的限制
- LIBXML_XINCLUDE - 实现XInclude替换
- LIBXML_ERR_ERROR - 获取可恢复的错误
- LIBXML_ERR_FATAL - 获取致命错误
- LIBXML_ERR_NONE - 获取无错误
- LIBXML_ERR_WARNING - 获取简单的警告
- LIBXML_VERSION - 获取libxml版本
- LIBXML_DOTTED_VERSION - 获取点分的libxml版本
返回值
成功时返回SimpleXMLElement对象。失败时为FALSE。
实例1
将格式良好的XML字符串转换为SimpleXMLElement对象,然后输出该对象的键和元素:
<?php
// http://www.manongjc.com/article/1630.html
$note=<<<XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<book>
<name>PHP</name>
<name>Java</name>
</book>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>
上面的代码生成以下结果。
SimpleXMLElement Object
(
[name] => Array
(
[0] => PHP
[1] => Java
)
)
实例2
输出XML字符串中每个元素的数据:
<?php
// http://www.manongjc.com/article/1630.html
$note=<<<XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<book>
<name>PHP</name>
<name>Java</name>
</book>
XML;
$xml=simplexml_load_string($note);
echo $xml->to . "\n";
echo $xml->from . "\n";
echo $xml->heading . "\n";
echo $xml->body;
?>
实例3
在XML字符串中为每个子节点输出元素的名称和数据:
<?php
// http://www.manongjc.com/article/1630.html
$note=<<<XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<book>
<name>PHP</name>
<name>Java</name>
</book>
XML;
$xml=simplexml_load_string($note);
echo $xml->getName() . "\n";
foreach($xml->children() as $child){
echo $child->getName() . ": " . $child . "\n";
}
?>
上面的代码生成以下结果。
book
name: PHP
name: Java
对象转成数组:
可以直接array()来转,但是有些情况不适用,数据结构会变。(未验证)
- 1.
- //PHP stdClass Object转array
- function object_array($array) {
- if(is_object($array)) {
- $array = (array)$array;
- }
- if(is_array($array)) {
- foreach($array as $key=>$value) {
- $array[$key] = object_array($value);
- }
- }
- return $array;
- }
- 2.
- $array = json_decode(json_encode(simplexml_load_string($xmlString)),TRUE);
- 3.
- function object2array_pre(&$object) {
- if (is_object($object)) {
- $arr = (array)($object);
- } else {
- $arr = &$object;
- }
- if (is_array($arr)) {
- foreach($arr as $varName => $varValue){
- $arr[$varName] = $this->object2array($varValue);
- }
- }
- return $arr;
- }
- 4.如果是10W的数据量的话,执行要进1s,结构再复杂些,可以达到3s,性能太差了,可以用以下替换:
- function object2array(&$object) {
- $object = json_decode( json_encode( $object),true);
- return $object;
- }