1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /** |
||
6 | * This file is part of the AuthnetJSON package. |
||
7 | * |
||
8 | * (c) John Conde <[email protected]> |
||
9 | * |
||
10 | * For the full copyright and license information, please view the LICENSE |
||
11 | * file that was distributed with this source code. |
||
12 | */ |
||
13 | |||
14 | namespace Authnetjson; |
||
15 | |||
16 | use Authnetjson\Exception\AuthnetInvalidCredentialsException; |
||
17 | use Authnetjson\Exception\AuthnetInvalidJsonException; |
||
18 | |||
19 | /** |
||
20 | * Handles a Webhook notification from the Authorize.Net Webhooks API |
||
21 | * |
||
22 | * @package AuthnetJSON |
||
23 | * @author John Conde <[email protected]> |
||
24 | * @copyright 2015 - 2023 John Conde <[email protected]> |
||
25 | * @license http://www.apache.org/licenses/LICENSE-2.0.html Apache License, Version 2.0 |
||
26 | * @link https://github.com/stymiee/authnetjson |
||
27 | * @see https://developer.authorize.net/api/reference/ |
||
28 | */ |
||
29 | class AuthnetWebhook |
||
30 | { |
||
31 | /** |
||
32 | * @var object SimpleXML object representing the Webhook notification |
||
33 | */ |
||
34 | private $webhook; |
||
35 | |||
36 | /** |
||
37 | * @var string JSON string that is the Webhook notification sent by Authorize.Net |
||
38 | */ |
||
39 | private $webhookJson; |
||
40 | |||
41 | /** |
||
42 | * @var array HTTP headers sent with the notification |
||
43 | */ |
||
44 | private $headers; |
||
45 | |||
46 | /** |
||
47 | * @var string Authorize.Net Signature Key |
||
48 | */ |
||
49 | private $signature; |
||
50 | |||
51 | /** |
||
52 | * Creates the response object with the response json returned from the API call |
||
53 | * |
||
54 | * @param string $signature Authorize.Net Signature Key |
||
55 | * @param string $payload Webhook Notification sent by Authorize.Net |
||
56 | * @param array $headers HTTP headers sent with Webhook. Optional if PHP is run as an Apache module |
||
57 | * @throws AuthnetInvalidCredentialsException |
||
58 | * @throws AuthnetInvalidJsonException |
||
59 | */ |
||
60 | 3 | public function __construct(string $signature, string $payload, array $headers = []) |
|
61 | { |
||
62 | 3 | $this->signature = $signature; |
|
63 | 3 | $this->webhookJson = $payload; |
|
64 | 3 | $this->headers = $headers; |
|
65 | 3 | if (empty($this->headers)) { |
|
66 | 2 | $this->headers = $this->getAllHeaders(); |
|
67 | } |
||
68 | 3 | if (empty($this->signature)) { |
|
69 | 1 | throw new AuthnetInvalidCredentialsException('You have not configured your signature properly.'); |
|
70 | } |
||
71 | 2 | if (($this->webhook = json_decode($this->webhookJson, false)) === null) { |
|
72 | 1 | throw new AuthnetInvalidJsonException('Invalid JSON sent in the Webhook notification'); |
|
73 | } |
||
74 | 1 | $this->headers = array_change_key_case($this->headers, CASE_UPPER); |
|
75 | 1 | } |
|
76 | |||
77 | /** |
||
78 | * Outputs the response JSON in a human-readable format |
||
79 | * |
||
80 | * @return string HTML table containing debugging information |
||
81 | */ |
||
82 | 1 | public function __toString() |
|
83 | { |
||
84 | 1 | $output = '<table id="authnet-webhook">' . "\n"; |
|
85 | 1 | $output .= '<caption>Authorize.Net Webhook</caption>' . "\n"; |
|
86 | 1 | $output .= '<tr><th colspan="2"><b>Response HTTP Headers</b></th></tr>' . "\n"; |
|
87 | 1 | $output .= '<tr><td colspan="2"><pre>' . "\n"; |
|
88 | 1 | $output .= var_export($this->headers, true) . "\n"; |
|
89 | 1 | $output .= '</pre></td></tr>' . "\n"; |
|
90 | 1 | $output .= '<tr><th colspan="2"><b>Response JSON</b></th></tr>' . "\n"; |
|
91 | 1 | $output .= '<tr><td colspan="2"><pre>' . "\n"; |
|
92 | 1 | $output .= $this->webhookJson . "\n"; |
|
93 | 1 | $output .= '</pre></td></tr>' . "\n"; |
|
94 | 1 | $output .= '</table>'; |
|
95 | |||
96 | 1 | return $output; |
|
97 | } |
||
98 | |||
99 | /** |
||
100 | * Gets a response variable from the Webhook notification |
||
101 | * |
||
102 | * @param string $var |
||
103 | * @return string requested variable from the API call response |
||
104 | */ |
||
105 | 1 | public function __get(string $var) |
|
106 | { |
||
107 | 1 | return $this->webhook->{$var}; |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * Validates a webhook signature to determine if the webhook is valid |
||
112 | * |
||
113 | * @return bool |
||
114 | */ |
||
115 | 3 | public function isValid(): bool |
|
116 | { |
||
117 | 3 | $hashedBody = strtoupper(hash_hmac('sha512', $this->webhookJson, $this->signature)); |
|
118 | 3 | return (isset($this->headers['X-ANET-SIGNATURE']) && |
|
119 | 3 | strtoupper(explode('=', $this->headers['X-ANET-SIGNATURE'])[1]) === $hashedBody); |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * Validates a webhook signature to determine if the webhook is valid |
||
124 | * |
||
125 | * @return string|null |
||
126 | */ |
||
127 | 1 | public function getRequestId(): ?string |
|
128 | { |
||
129 | 1 | return $this->headers['X-REQUEST-ID'] ?? null; |
|
130 | } |
||
131 | |||
132 | /** |
||
133 | * Retrieves all HTTP headers of a given request |
||
134 | * |
||
135 | * @return array |
||
136 | */ |
||
137 | 1 | protected function getAllHeaders(): array |
|
138 | { |
||
139 | 1 | if (function_exists('apache_request_headers')) { |
|
140 | $headers = apache_request_headers(); |
||
141 | } else { |
||
142 | 1 | $headers = []; |
|
143 | 1 | foreach ($_SERVER as $key => $value) { |
|
144 | 1 | if (strpos($key, 'HTTP_') === 0) { |
|
145 | 1 | $headers[str_replace('_', '-', substr($key, 5))] = $value; |
|
146 | } |
||
147 | } |
||
148 | } |
||
149 | 1 | return $headers ?: []; |
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
150 | } |
||
151 | } |
||
152 |