Cryptomus.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <?php
  2. namespace App\Utils\Payments;
  3. use App\Utils\Library\PaymentHelper;
  4. use App\Utils\Library\Templates\Gateway;
  5. use Http;
  6. use Illuminate\Http\JsonResponse;
  7. use Illuminate\Http\Request;
  8. use Log;
  9. use Response;
  10. class Cryptomus implements Gateway
  11. {
  12. private const API_URL = 'https://api.cryptomus.com/';
  13. private string $apiKey;
  14. private string $mid;
  15. public function __construct()
  16. {
  17. $this->mid = sysConfig('cryptomus_merchant_uuid');
  18. $this->apiKey = sysConfig('cryptomus_api_key');
  19. }
  20. public static function metadata(): array
  21. {
  22. return [
  23. 'key' => 'cryptomus',
  24. 'method' => ['other'],
  25. 'settings' => [
  26. 'cryptomus_merchant_uuid' => null,
  27. 'cryptomus_api_key' => null,
  28. ],
  29. ];
  30. }
  31. public function purchase(Request $request): JsonResponse
  32. {
  33. $payment = PaymentHelper::createPayment(auth()->id(), $request->input('id'), $request->input('amount'));
  34. $result = $this->createOrder([
  35. 'amount' => $payment->amount,
  36. 'currency' => sysConfig('standard_currency'),
  37. 'order_id' => $payment->trade_no,
  38. 'lifetime' => 900,
  39. // 'network' => '',
  40. 'is_payment_multiple' => false,
  41. 'url_return' => route('shop.index'),
  42. 'url_success' => route('invoice.index'),
  43. 'url_callback' => route('payment.notify', ['method' => 'cryptomus']),
  44. ]);
  45. if (isset($result['state'], $result['result']['url']) && $result['state'] === 0) {
  46. $payment->update(['url' => $result['result']['url']]);
  47. return Response::json(['status' => 'success', 'url' => $result['result']['url'], 'message' => trans('user.payment.order_creation.success')]);
  48. }
  49. $payment->failed();
  50. if (isset($result['message'])) {
  51. Log::alert('【Cryptomus】创建订单错误:'.$result['message']);
  52. return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
  53. }
  54. if (! isset($result['result']['url'])) {
  55. Log::alert('【Cryptomus】创建订单错误:未获取到支付链接'.var_export($result, true));
  56. }
  57. return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
  58. }
  59. private function createOrder(array $params): array
  60. {
  61. $response = Http::withHeaders(['merchant' => $this->mid, 'sign' => $this->sign($params)])->asJson()->post(self::API_URL.'v1/payment', $params);
  62. if ($response->ok()) {
  63. return $response->json();
  64. }
  65. Log::alert('【Cryptomus】创建订单失败:'.var_export($response->json(), true));
  66. return ['status' => 'fail', 'message' => '获取失败!请检查配置信息'];
  67. }
  68. private function sign(array|string $data): string
  69. {
  70. if (isset($params['sign'])) {
  71. unset($params['sign']);
  72. }
  73. return md5(base64_encode(json_encode($data, JSON_UNESCAPED_UNICODE)).$this->apiKey);
  74. }
  75. public function notify(Request $request): void
  76. {
  77. if (! $this->verify($request->post())) {
  78. exit(400);
  79. }
  80. if ($request->has(['is_final', 'status', 'order_id']) && in_array($request->input('status'), ['paid', 'paid_over'], true) && PaymentHelper::paymentReceived($request->input(['order_id']))) {
  81. exit(200);
  82. }
  83. Log::error('【Cryptomus】交易失败:'.var_export($request->all(), true));
  84. exit(500);
  85. }
  86. private function verify(array $params): bool
  87. {
  88. return hash_equals($params['sign'], $this->sign($params));
  89. }
  90. }