feieyunCallbackUtil.php 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <?php
  2. namespace common\components;
  3. use Yii;
  4. /**
  5. * 飞鹅云打印回调验签(SHA256WithRSA)
  6. * 文档:http://help.feieyun.com/#/home/doc/zh;nav=1-8
  7. */
  8. class feieyunCallbackUtil
  9. {
  10. /**
  11. * 飞鹅公钥文件路径
  12. */
  13. public static function getPublicKeyPath()
  14. {
  15. return Yii::getAlias('@app/web/feieyun/public.key');
  16. }
  17. /**
  18. * 组装待验签字符串:剔除 sign 与空值,按参数名 ASCII 升序拼接
  19. */
  20. public static function buildSignContent(array $params)
  21. {
  22. unset($params['sign']);
  23. $filtered = [];
  24. foreach ($params as $key => $value) {
  25. if ($value === null || $value === '') {
  26. continue;
  27. }
  28. $filtered[(string)$key] = (string)$value;
  29. }
  30. ksort($filtered, SORT_STRING);
  31. $parts = [];
  32. foreach ($filtered as $key => $value) {
  33. $parts[] = $key . '=' . $value;
  34. }
  35. return implode('&', $parts);
  36. }
  37. /**
  38. * 校验飞鹅回调签名
  39. */
  40. public static function verify(array $params)
  41. {
  42. $sign = trim((string)($params['sign'] ?? ''));
  43. if ($sign === '') {
  44. return false;
  45. }
  46. $publicKeyPath = self::getPublicKeyPath();
  47. if (!is_file($publicKeyPath)) {
  48. Yii::error('飞鹅公钥文件不存在: ' . $publicKeyPath, __METHOD__);
  49. return false;
  50. }
  51. $publicKey = file_get_contents($publicKeyPath);
  52. if ($publicKey === false || trim($publicKey) === '') {
  53. Yii::error('飞鹅公钥文件读取失败: ' . $publicKeyPath, __METHOD__);
  54. return false;
  55. }
  56. $signContent = self::buildSignContent($params);
  57. $signature = base64_decode($sign, true);
  58. if ($signature === false) {
  59. Yii::warning('飞鹅回调 sign Base64 解码失败', __METHOD__);
  60. return false;
  61. }
  62. $key = openssl_pkey_get_public($publicKey);
  63. if ($key === false) {
  64. Yii::error('飞鹅公钥解析失败: ' . openssl_error_string(), __METHOD__);
  65. return false;
  66. }
  67. $result = openssl_verify($signContent, $signature, $key, OPENSSL_ALGO_SHA256);
  68. if (PHP_VERSION_ID < 80000) {
  69. openssl_free_key($key);
  70. }
  71. return $result === 1;
  72. }
  73. }