<?php
use SoapParam;
use SoapClient;
class Soap extends SoapClient
{
/**
* @var string 请求方法
*/
private $_func;
/**
* @var array 请求方法的参数
*/
private $_params = [];
/**
* @var bool 自定义xml
*/
private $_is_custom;
/**
* @description: soap客户端
* @param string|null $wsdl wsdl文件uri,空代表不使用wsdl模式
* @param array $options 非wsdl模式下必须指定location(接口地址)和uri(与server端保持一致)
* @return {*}
*/
public function __construct($wsdl, $options = [])
{
parent::__construct($wsdl, $options);
}
/**
* @description: 请求SOAP请求,内置方法,调用soap请求时会自动执行此方法
* @return {*}
*/
public function __doRequest($request, $location, $action, $version, $oneWay = NULL)
{
if ($this->_is_custom) {
$request = $this->_customXml();
}
return parent::__doRequest($request, $location, $action, $version, $oneWay);
}
/**
* @description: 自定义xml,处理与服务端格式不符的问题
* @return string
*/
private function _customXml()
{
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>';
$xml .= '<tem:'. $this->_func .'>';
foreach ($this->_params as $key => $val) {
$xml .= $this->_customXmlKey('tem', $key, $val);
}
$xml .= '</tem:'. $this->_func .'>';
$xml .= '</soapenv:Body>
</soapenv:Envelope>';
return $xml;
}
/**
* @description: 自定义xml中的参数设置
* @param string $prefix 前缀
* @param string $key
* @param string $val
* @return string
*/
private function _customXmlKey($prefix, $key, $val)
{
return "<$prefix:$key>$val</$prefix:$key>";
}
/**
* @description: 请求
* @param string $func 请求方法
* @param array $params 请求方法的参数,如果不自定义xml,需要在数组第一位加一个key,因为第一个key会丢失
* @param bool $is_custom 是否自定义xml
* @return json|xml
*/
public function requests($func, $params = [], $is_custom = false)
{
$this->_func = $func;
$this->_params = $params;
$this->_is_custom = $is_custom;
try {
$result1 = $this->$func(...$this->_dealParams($params)); //执行soap请求
$varibale = $func . 'Result';
$result = $result1->$varibale;
if (strpos($result, 'Could not connect to host') !== false) {
return json_encode(['code' => false, 'msg' => '请求失败']);
}
return $result;
} catch (\Exception $e) {
$result = $e->getMessage();
return json_encode(['code' => false, 'msg' => '请求错误']);
} finally {
$this->_log($result);
}
}
/**
* @description: 预处理请求参数
* @param array $params 参数
* @return array
*/
private function _dealParams($params)
{
$result = [];
foreach ($params as $key => $param) {
$result[] = new SoapParam($param, $key);
}
return $result;
}
/**
* @description: 记录日志
* @param {*} $result
* @return {*}
*/
private function _log($result)
{
error_log($this->_get_log_content($result), 3, $this->_generate_log_file());
}
/**
* @description: 获取日志内容
* @return string
*/
private function _get_log_content($result)
{
return '[ '.date('Y-m-d H:i:s').' ] ' . $this->_func . ' ' . PHP_EOL .
'[ REQUEST HEADER ] ' . $this->__getLastRequestHeaders() . PHP_EOL .
'[ PARAM ] ' . PHP_EOL .
json_encode($this->_params, JSON_UNESCAPED_UNICODE) . PHP_EOL .
'[ RESPONSE HEADER ] ' . PHP_EOL .
$this->__getLastResponseHeaders() . PHP_EOL .
'[ RESPONSE BODY ] ' . PHP_EOL .
$result;
}
/**
* @description: 获取日志文件路径
* @return string
*/
private function _generate_log_file()
{
$this->_log_path = './log/'.date('Ym').'/soap/';
if (!is_dir($this->_log_path)) {
mkdir($this->_log_path, 0777, true);
}
$log_file = $this->_log_path . date('d') . '.log';
if (is_file($log_file) && filesize($log_file) > 2097152) {
rename($log_file, $this->_log_path. date('dHis') . '_' . uniqid() . '.log');
}
return $log_file;
}
}
调用
// trace启用对请求的跟踪,因此可以回溯故障,用于调试
$soap = new Soap('http://xxx.xxxxxx.xx/xxx.asmx?WSDL', ['trace' => true]);
$result = $soap->requests($func, $param, true);