如何在PHP中读取传入的SOAP请求?问题排查与示例需求
处理SOAP请求读取问题的解决方案
问题概述
现有如下SOAP请求:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"> <soapenv:Body> <tem:ApplyTransactionRequest xmlns:tem="http://tempuri.org/" xmlns:at="http://cps.huawei.com/cpsinterface/goa/at" xmlns:goa="http://cps.huawei.com/cpsinterface/goa"> <at:Header> <goa:CommandID>CheckInformation</goa:CommandID> <goa:Version>1.0</goa:Version> <goa:LoginID>NGOLoanPay</goa:LoginID> <goa:Password>e7L/g2/isbOu5Q6fHW3CAYtWgGYv8Av64BQet3WBQpmraV3HTzvlMBdQzGx056gY</goa:Password> <goa:Timestamp>20220110111810</goa:Timestamp> <goa:ConversationID>9DJ906XRUD</goa:ConversationID> <goa:HeaderExtension> <goa:Parameter> <goa:Key>name</goa:Key> <goa:Value>cps</goa:Value> </goa:Parameter> </goa:HeaderExtension> </at:Header> <at:Body> <at:Parameters> <goa:Parameter> <goa:Key>IDNumber</goa:Key> <goa:Value>220214000126</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>FullName</goa:Key> <goa:Value>MAYA</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>InquiryType</goa:Key> <goa:Value>01</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>InquiryMode</goa:Key> <goa:Value>02</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>FirstName</goa:Key> <goa:Value></goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>InitiatorID</goa:Key> <goa:Value>8801301712997</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>ChannelCode</goa:Key> <goa:Value>10</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>channelCode</goa:Key> <goa:Value>10</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>LastName</goa:Key> <goa:Value></goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>PartnerID</goa:Key> <goa:Value>MFI</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>ChkAmount</goa:Key> <goa:Value></goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>EndMonth</goa:Key> <goa:Value></goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>ExtendedParmeter1</goa:Key> <goa:Value></goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>SubID</goa:Key> <goa:Value></goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>AccountID</goa:Key> <goa:Value>201004000589</goa:Value> </goa:Parameter> <goa:Parameter> <goa:Key>StartMonth</goa:Key> <goa:Value></goa:Value> </goa:Parameter> </at:Parameters> </at:Body> </tem:ApplyTransactionRequest> </soapenv:Body> </soapenv:Envelope>
尝试用以下代码读取请求,但无法正常获取内容:
function CheckInfoAPI() { $soap_request = file_get_contents("php://input"); $parser=xml_parser_create(); xml_parse_into_struct($parser,$soap_request,$request_array); xml_parser_free($parser); var_dump($parser); }
执行后返回:
resource(49) of type (Unknown)
需要解决如何获取请求中的LoginID、Password等字段,实现根据不同用户返回不同响应。
代码问题分析
- 调用
xml_parser_free($parser)后,XML解析器资源已被释放,此时再var_dump($parser)自然会显示Unknown类型的资源,属于无效操作。 - 实际解析结果存储在
$request_array变量中,但代码未对其进行处理;而且原生XML解析函数处理带命名空间的SOAP请求会非常繁琐,容易出错。
推荐解决方案:使用SimpleXML处理带命名空间的SOAP请求
PHP的SimpleXML扩展可以更便捷地处理带命名空间的XML,以下是适配该SOAP请求的完整示例:
function CheckInfoAPI() { // 读取SOAP请求内容 $soapRequest = file_get_contents("php://input"); // 加载XML内容 $xml = simplexml_load_string($soapRequest); // 注册SOAP请求中用到的命名空间 $xml->registerXPathNamespace('soapenv', 'http://www.w3.org/2003/05/soap-envelope'); $xml->registerXPathNamespace('tem', 'http://tempuri.org/'); $xml->registerXPathNamespace('at', 'http://cps.huawei.com/cpsinterface/goa/at'); $xml->registerXPathNamespace('goa', 'http://cps.huawei.com/cpsinterface/goa'); // 获取Header中的LoginID和Password $loginId = (string)$xml->xpath('//goa:LoginID')[0]; $password = (string)$xml->xpath('//goa:Password')[0]; // 获取其他Header字段 $commandId = (string)$xml->xpath('//goa:CommandID')[0]; $timestamp = (string)$xml->xpath('//goa:Timestamp')[0]; // 解析Parameters中的键值对为关联数组 $parameters = []; $paramNodes = $xml->xpath('//goa:Parameter'); foreach ($paramNodes as $node) { $key = (string)$node->Key; $value = (string)$node->Value; $parameters[$key] = $value; } // 根据LoginID等信息生成对应的响应 $responseContent = match ($loginId) { 'NGOLoanPay' => '验证通过,返回用户专属数据', default => '未知用户,返回默认响应' }; // 输出SOAP响应(复用已有响应生成逻辑) generateSoapResponse($responseContent); // 调试用:输出获取到的数据 // var_dump($loginId, $password, $parameters); } // 模拟已有的响应生成函数 function generateSoapResponse($content) { header('Content-Type: application/soap+xml; charset=utf-8'); echo '<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"> <soapenv:Body> <tem:ApplyTransactionResponse xmlns:tem="http://tempuri.org/"> <Result>'.$content.'</Result> </tem:ApplyTransactionResponse> </soapenv:Body> </soapenv:Envelope>'; }
代码说明
- 读取请求:通过
file_get_contents("php://input")获取原始SOAP请求内容。 - 加载XML:使用
simplexml_load_string将XML字符串转换为SimpleXMLElement对象。 - 注册命名空间:由于SOAP请求包含多个命名空间,需要通过
registerXPathNamespace注册后,才能用XPath精准定位节点。 - 提取字段:通过XPath表达式定位
LoginID、Password等节点,转换为字符串类型获取值。 - 解析参数:遍历所有
goa:Parameter节点,将键值对整理为关联数组,方便后续使用。 - 生成响应:根据获取到的用户信息(如
LoginID)生成对应的SOAP响应。
备选方案:使用PHP SOAP扩展
如果服务器启用了PHP SOAP扩展,也可以直接创建SOAP服务端,自动处理请求解析:
class CheckInfoService { public function ApplyTransactionRequest($params) { // $params会自动包含SOAP请求中的所有参数 $loginId = $params['Header']['LoginID']; $password = $params['Header']['Password']; // 根据用户信息返回响应 if ($loginId === 'NGOLoanPay') { return ['Result' => '验证通过,返回专属数据']; } else { return ['Result' => '未知用户']; } } } // 创建SOAP服务端 $server = new SoapServer(null, [ 'uri' => 'http://tempuri.org/', 'soap_version' => SOAP_1_2 // 对应SOAP 1.2版本,与请求匹配 ]); $server->setClass('CheckInfoService'); $server->handle();
这种方式不需要手动解析XML,SOAP扩展会自动将请求映射为对象或数组,开发效率更高。
内容的提问来源于stack exchange,提问作者user1643268
相关产品推荐
相关产品推荐

