WechatPay2Validator.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <?php
  2. /**
  3. * WechatPay2Validator
  4. * PHP version 5
  5. *
  6. * @category Class
  7. * @package WechatPay
  8. * @author WeChat Pay Team
  9. * @link https://pay.weixin.qq.com
  10. */
  11. namespace WechatPay\GuzzleMiddleware\Auth;
  12. use Psr\Http\Message\ResponseInterface;
  13. use WechatPay\GuzzleMiddleware\Validator;
  14. use WechatPay\GuzzleMiddleware\Auth\Verifier;
  15. /**
  16. * WechatPay2Validator
  17. *
  18. * @category Class
  19. * @package WechatPay\GuzzleMiddleware\Auth
  20. * @author WeChat Pay Team
  21. * @link https://pay.weixin.qq.com
  22. */
  23. class WechatPay2Validator implements Validator
  24. {
  25. /**
  26. * sign verifier
  27. *
  28. * @var Verifier
  29. */
  30. protected $verifier;
  31. /**
  32. * Constructor
  33. */
  34. public function __construct(Verifier $verifier)
  35. {
  36. $this->verifier = $verifier;
  37. }
  38. /**
  39. * Validate Response
  40. *
  41. * @param ResponseInterface $response Api response to validate
  42. *
  43. * @return bool
  44. */
  45. public function validate(ResponseInterface $response)
  46. {
  47. $serialNo = $this->getHeader($response, 'Wechatpay-Serial');
  48. $sign = $this->getHeader($response, 'Wechatpay-Signature');
  49. $timestamp = $this->getHeader($response, 'Wechatpay-TimeStamp');
  50. $nonce = $this->getHeader($response, 'Wechatpay-Nonce');
  51. if (!isset($serialNo, $sign, $timestamp, $nonce)) {
  52. return false;
  53. }
  54. if (!$this->checkTimestamp($timestamp)) {
  55. // log here
  56. return false;
  57. }
  58. $body = $this->getBody($response);
  59. $message = "$timestamp\n$nonce\n$body\n";
  60. return $this->verifier->verify($serialNo, $message, $sign);
  61. }
  62. /**
  63. * Build message to sign
  64. *
  65. * @param string $nonce Nonce string
  66. * @param integer $timestamp Unix timestamp
  67. * @param RequestInterface $request Api request
  68. *
  69. * @return string
  70. */
  71. protected function getHeader(ResponseInterface $response, $name)
  72. {
  73. $values = $response->getHeader($name);
  74. return empty($values) ? null : $values[count($values) - 1];
  75. }
  76. /**
  77. * Check whether timestamp is valid
  78. *
  79. * @param integer $timestamp Unix timestamp
  80. *
  81. * @return bool
  82. */
  83. protected function checkTimestamp($timestamp)
  84. {
  85. // reject responses beyond 5 minutes
  86. return \abs((int)$timestamp - \time()) <= 300;
  87. }
  88. /**
  89. * Build message to sign
  90. *
  91. * @param string $nonce Nonce string
  92. * @param integer $timestamp Unix timestamp
  93. * @param RequestInterface $request Api request
  94. *
  95. * @return string
  96. */
  97. protected function getBody(ResponseInterface $response)
  98. {
  99. $body = '';
  100. $bodyStream = $response->getBody();
  101. // non-seekable stream need to be handled by the caller
  102. if ($bodyStream->isSeekable()) {
  103. $body = (string)$bodyStream;
  104. $bodyStream->rewind();
  105. }
  106. return $body;
  107. }
  108. }