ApiSign.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: dingran
  5. * Date: 2020/3/2
  6. * Time: 下午2:19
  7. */
  8. namespace app\common\services;
  9. class ApiSign
  10. {
  11. /** 请求网关 */
  12. private $gateway = '';
  13. /** 密钥 */
  14. private $key;
  15. /** 平台标识码 */
  16. private $unique_code;
  17. /** 请求的参数 */
  18. private $parameters;
  19. private $sign_type = 'MD5';
  20. public function __construct()
  21. {
  22. }
  23. public function setGateWay($gateWay)
  24. {
  25. $this->gateway = $gateWay;
  26. return $this;
  27. }
  28. public function setKey($key)
  29. {
  30. $this->key = $key;
  31. return $this;
  32. }
  33. public function setUniqueCode($code)
  34. {
  35. $this->unique_code = $code;
  36. return $this;
  37. }
  38. public function setSignType($signType)
  39. {
  40. $this->sign_type = $signType;
  41. return $this;
  42. }
  43. /**
  44. *获取参数值
  45. */
  46. function getParameter($parameter) {
  47. return isset($this->parameters[$parameter]) ? $this->parameters[$parameter] : '';
  48. }
  49. /**
  50. *设置参数值
  51. */
  52. function setParameter($parameter, $parameterValue) {
  53. $this->parameters[$parameter] = $parameterValue;
  54. }
  55. /**
  56. * 一次性设置参数
  57. */
  58. function setReqParams($post, $filterField = null){
  59. if($filterField !== null){
  60. forEach($filterField as $k=>$v){
  61. unset($post[$v]);
  62. }
  63. }
  64. //判断是否存在空值,空值不提交
  65. forEach($post as $k=>$v){
  66. if(empty($v)){
  67. unset($post[$k]);
  68. }
  69. }
  70. $this->parameters = $post;
  71. }
  72. /**
  73. *获取所有请求的参数
  74. *@return array
  75. */
  76. function getAllParameters() {
  77. return $this->parameters;
  78. }
  79. /**
  80. * 取得链接
  81. */
  82. public function getLink()
  83. {
  84. $para = $this->buildRequestPara();
  85. return $this->gateway . '?' . $this->createLinkstringUrlencode($para);
  86. }
  87. /**
  88. * 验证消息是否是合法消息
  89. */
  90. public function verify()
  91. {
  92. // 判断请求是否为空
  93. if (empty($_POST) && empty($_GET)) {
  94. return false;
  95. }
  96. $data = $_POST ?: $_GET;
  97. $this->setReqParams($data);
  98. // 生成签名结果
  99. $is_sign = $this->getSignVeryfy($data['sign']);
  100. if ($is_sign) {
  101. return true;
  102. } else {
  103. return false;
  104. }
  105. }
  106. /**
  107. * 生成要请求的参数数组
  108. * @param $para_temp 请求前的参数数组
  109. * @return 要请求的参数数组
  110. */
  111. private function buildRequestPara()
  112. {
  113. //除去待签名参数数组中的空值和签名参数
  114. $para_filter = $this->paraFilter();
  115. //对待签名参数数组排序
  116. $para_sort = $this->argSort($para_filter);
  117. //生成签名结果
  118. $mysign = $this->buildRequestMysign($para_sort);
  119. //签名结果与签名方式加入请求提交参数组中
  120. $para_sort['sign'] = $mysign;
  121. return $para_sort;
  122. }
  123. /**
  124. * 生成签名
  125. * @param $para_temp 请求前的参数数组
  126. * @return 签名
  127. */
  128. public function generateSign()
  129. {
  130. //除去待签名参数数组中的空值和签名参数
  131. $para_filter = $this->paraFilter();
  132. //对待签名参数数组排序
  133. $para_sort = $this->argSort($para_filter);
  134. //生成签名结果
  135. $mysign = $this->buildRequestMysign($para_sort);
  136. return $mysign;
  137. }
  138. /**
  139. * 除去数组中的空值和签名参数
  140. * @param $para 签名参数组
  141. * return 去掉空值与签名参数后的新签名参数组
  142. */
  143. private function paraFilter()
  144. {
  145. $para_filter = array();
  146. foreach($this->parameters as $k => $v) {
  147. if("" != $v && "sign" != $k) {
  148. $para_filter[$k] = $v;
  149. }
  150. }
  151. return $para_filter;
  152. }
  153. /**
  154. * 对数组排序
  155. * @param $para 排序前的数组
  156. * return 排序后的数组
  157. */
  158. private function argSort($para)
  159. {
  160. ksort($para);
  161. reset($para);
  162. return $para;
  163. }
  164. /**
  165. * 生成签名结果
  166. * @param $para_sort 已排序要签名的数组
  167. * return 签名结果字符串
  168. */
  169. private function buildRequestMysign($para_sort)
  170. {
  171. //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  172. $prestr = $this->createLinkstring($para_sort);
  173. $mysign = '';
  174. switch (strtoupper(trim($this->sign_type))) {
  175. case 'MD5':
  176. $mysign = $this->md5Sign($prestr, $this->key);
  177. break;
  178. default:
  179. $mysign = '';
  180. }
  181. return $mysign;
  182. }
  183. /**
  184. * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  185. * @param $para 需要拼接的数组
  186. * return 拼接完成以后的字符串
  187. */
  188. private function createLinkstring($para)
  189. {
  190. $arg = '';
  191. foreach ($para as $key => $val) {
  192. $arg .= $key . '=' . urlencode($val) . '&';
  193. }
  194. //去掉最后一个&字符
  195. $arg = substr($arg, 0, count($arg) - 2);
  196. //如果存在转义字符,那么去掉转义
  197. if (get_magic_quotes_gpc()) {
  198. $arg = stripslashes($arg);
  199. }
  200. return $arg;
  201. }
  202. /**
  203. * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
  204. * @param $para 需要拼接的数组
  205. * return 拼接完成以后的字符串
  206. */
  207. private function createLinkstringUrlencode($para)
  208. {
  209. $arg = '';
  210. foreach ($para as $key => $val) {
  211. $arg .= $key . '=' . urlencode($val) . '&';
  212. }
  213. //去掉最后一个&字符
  214. $arg = substr($arg, 0, count($arg) - 2);
  215. //如果存在转义字符,那么去掉转义
  216. if (get_magic_quotes_gpc()) {
  217. $arg = stripslashes($arg);
  218. }
  219. return $arg;
  220. }
  221. /**
  222. * 签名字符串
  223. * @param $prestr 需要签名的字符串
  224. * @param $key 私钥
  225. * return 签名结果
  226. */
  227. private function md5Sign($prestr, $key)
  228. {
  229. $prestr = $prestr . $key;
  230. return md5($prestr);
  231. }
  232. /**
  233. * 验证签名
  234. * @param $prestr 需要签名的字符串
  235. * @param $sign 签名结果
  236. * @param $key 私钥
  237. * return 签名结果
  238. */
  239. private function md5Verify($prestr, $sign, $key)
  240. {
  241. $prestr = $prestr . $key;
  242. $mysgin = md5($prestr);
  243. if ($mysgin == $sign) {
  244. return true;
  245. } else {
  246. return false;
  247. }
  248. }
  249. /**
  250. * 获取返回时的签名验证结果
  251. * @param $para_temp 通知返回来的参数数组
  252. * @param $sign 返回的签名结果
  253. * @return bool 签名验证结果
  254. */
  255. public function getSignVeryfy($sign)
  256. {
  257. //除去待签名参数数组中的空值和签名参数
  258. $para_filter = $this->paraFilter();
  259. //对待签名参数数组排序
  260. $para_sort = $this->argSort($para_filter);
  261. //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  262. $prestr = $this->createLinkstring($para_sort);
  263. $is_sgin = false;
  264. $key = $this->unique_code ? $this->key.$this->unique_code : $this->key;
  265. switch (strtoupper(trim($this->sign_type))) {
  266. case 'MD5':
  267. $is_sgin = $this->md5Verify($prestr, $sign, $key);
  268. break;
  269. default:
  270. $is_sgin = false;
  271. }
  272. return $is_sgin;
  273. }
  274. }