1
|
|
|
<?php |
2
|
|
|
namespace phpbu\App\Log; |
3
|
|
|
|
4
|
|
|
use phpbu\App\Exception; |
5
|
|
|
use phpbu\App\Event; |
6
|
|
|
use phpbu\App\Listener; |
7
|
|
|
use phpbu\App\Result; |
8
|
|
|
use phpbu\App\Util\Arr; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Webhook Logger |
12
|
|
|
* |
13
|
|
|
* @package phpbu |
14
|
|
|
* @subpackage Log |
15
|
|
|
* @author Cees Vogel <[email protected]> |
16
|
|
|
* @author Sebastian Feldmann <[email protected]> |
17
|
|
|
* @copyright Sebastian Feldmann <[email protected]> |
18
|
|
|
* @license https://opensource.org/licenses/MIT The MIT License (MIT) |
19
|
|
|
* @link https://phpbu.de/ |
20
|
|
|
* @since Class available since Release 5.0.0 |
21
|
|
|
*/ |
22
|
|
|
class Webhook implements Listener, Logger |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* Start time |
26
|
|
|
* |
27
|
|
|
* @var float |
28
|
|
|
*/ |
29
|
|
|
private $start; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Uri to call |
33
|
|
|
* |
34
|
|
|
* @var string |
35
|
|
|
*/ |
36
|
|
|
private $uri; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Request method GET|POST |
40
|
|
|
* |
41
|
|
|
* @var string |
42
|
|
|
*/ |
43
|
|
|
private $method; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Basic auth username |
47
|
|
|
* |
48
|
|
|
* @var string |
49
|
|
|
*/ |
50
|
|
|
private $username; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Basic auth password |
54
|
|
|
* |
55
|
|
|
* @var string |
56
|
|
|
*/ |
57
|
|
|
private $password; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Request content type |
61
|
|
|
* |
62
|
|
|
* @var string |
63
|
|
|
*/ |
64
|
|
|
private $contentType; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Body template to use |
68
|
|
|
* |
69
|
|
|
* @var string |
70
|
|
|
*/ |
71
|
|
|
private $template; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* List of available default formatter |
75
|
|
|
* |
76
|
|
|
* @var array |
77
|
|
|
*/ |
78
|
|
|
private $availableFormatter = [ |
79
|
|
|
'multipart/form-data' => '\\phpbu\\App\\Log\\ResultFormatter\\FormData', |
80
|
|
|
'application/json' => '\\phpbu\\App\\Log\\ResultFormatter\\Json', |
81
|
|
|
'application/xml' => '\\phpbu\\App\\Log\\ResultFormatter\\Xml' |
82
|
|
|
]; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Constructor will only set the start time to be able to log duration |
86
|
|
|
*/ |
87
|
7 |
|
public function __construct() |
88
|
|
|
{ |
89
|
7 |
|
$this->start = microtime(true); |
90
|
7 |
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Returns an array of event names this subscriber wants to listen to. |
94
|
|
|
* |
95
|
|
|
* The array keys are event names and the value can be: |
96
|
|
|
* |
97
|
|
|
* - The method name to call (priority defaults to 0) |
98
|
|
|
* - An array composed of the method name to call and the priority |
99
|
|
|
* - An array of arrays composed of the method names to call and respective |
100
|
|
|
* priorities, or 0 if unset |
101
|
|
|
* |
102
|
|
|
* @return array The event names to listen to |
103
|
|
|
*/ |
104
|
1 |
|
public static function getSubscribedEvents() |
105
|
|
|
{ |
106
|
|
|
return [ |
107
|
1 |
|
'phpbu.app_end' => 'onPhpbuEnd', |
108
|
|
|
]; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Setup the logger. |
113
|
|
|
* |
114
|
|
|
* @see \phpbu\App\Log\Logger::setup |
115
|
|
|
* @param array $options |
116
|
|
|
* @throws \phpbu\App\Exception |
117
|
|
|
*/ |
118
|
7 |
|
public function setup(array $options) |
119
|
|
|
{ |
120
|
7 |
|
if (empty($options['uri'])) { |
121
|
1 |
|
throw new Exception('no uri given'); |
122
|
|
|
} |
123
|
6 |
|
$this->uri = $options['uri']; |
124
|
6 |
|
$this->method = Arr::getValue($options, 'method', 'GET'); |
125
|
6 |
|
$this->username = Arr::getValue($options, 'username', ''); |
126
|
6 |
|
$this->password = Arr::getValue($options, 'password', ''); |
127
|
6 |
|
$this->template = Arr::getValue($options, 'template', ''); |
128
|
6 |
|
$this->contentType = Arr::getValue($options, 'contentType', 'multipart/form-data'); |
129
|
6 |
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* phpbu end event. |
133
|
|
|
* |
134
|
|
|
* @param \phpbu\App\Event\App\End $event |
135
|
|
|
*/ |
136
|
6 |
|
public function onPhpbuEnd(Event\App\End $event) |
137
|
|
|
{ |
138
|
6 |
|
$result = $event->getResult(); |
139
|
6 |
|
$data = $this->getQueryStringData($result); |
140
|
6 |
|
$uri = $this->method === 'GET' ? $this->buildGetUri($data) : $this->uri; |
141
|
6 |
|
$formatter = $this->getBodyFormatter($result); |
|
|
|
|
142
|
5 |
|
$body = $formatter->format($result); |
143
|
|
|
|
144
|
5 |
|
$this->fireRequest($uri, $body); |
145
|
1 |
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Builds the final request uri for GET requests. |
149
|
|
|
* |
150
|
|
|
* @param array $data |
151
|
|
|
* @return string |
152
|
|
|
*/ |
153
|
2 |
|
private function buildGetUri(array $data) : string |
154
|
|
|
{ |
155
|
2 |
|
$glue = strpos($this->uri, '?') !== false ? '&' : '?'; |
156
|
2 |
|
return $this->uri . $glue . http_build_query($data); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Return the request body template. |
161
|
|
|
* If template and body are set the body supersedes the template setting. |
162
|
|
|
* |
163
|
|
|
* @return \phpbu\App\Log\ResultFormatter |
164
|
|
|
* @throws \phpbu\App\Exception |
165
|
|
|
*/ |
166
|
6 |
|
private function getBodyFormatter() : ResultFormatter |
167
|
|
|
{ |
168
|
6 |
|
if (!empty($this->template)) { |
169
|
1 |
|
return new ResultFormatter\Template($this->template); |
170
|
|
|
} |
171
|
|
|
|
172
|
5 |
|
if (!isset($this->availableFormatter[$this->contentType])) { |
173
|
1 |
|
throw new Exception('no default formatter for content-type: ' . $this->contentType); |
174
|
|
|
} |
175
|
4 |
|
$class = $this->availableFormatter[$this->contentType]; |
176
|
4 |
|
return new $class(); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Method will use the input Result to replace the placeholders in $this->jsonOutput or return an array with |
181
|
|
|
* the default values. |
182
|
|
|
* |
183
|
|
|
* @param $result \phpbu\App\Result |
184
|
|
|
* @return array: will return array placeholders are replaced with correct data |
|
|
|
|
185
|
|
|
*/ |
186
|
6 |
|
private function getQueryStringData(Result $result) : array |
187
|
|
|
{ |
188
|
6 |
|
$end = microtime(true); |
189
|
|
|
|
190
|
|
|
return [ |
191
|
6 |
|
'status' => $result->allOk() ? 0 : 1, |
192
|
6 |
|
'timestamp' => (int) $this->start, |
193
|
6 |
|
'duration' => round($end - $this->start, 4), |
194
|
6 |
|
'err-cnt' => $result->errorCount(), |
195
|
6 |
|
'bak-cnt' => count($result->getBackups()), |
196
|
6 |
|
'bak-fail' => $result->backupsFailedCount(), |
197
|
|
|
]; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Execute the request to the webhook uri. |
203
|
|
|
* |
204
|
|
|
* @param string $uri |
205
|
|
|
* @param string $body |
206
|
|
|
* @throws \phpbu\App\Exception |
207
|
|
|
*/ |
208
|
5 |
|
protected function fireRequest(string $uri, string $body = '') |
209
|
|
|
{ |
210
|
5 |
|
$headers = []; |
211
|
|
|
$options = [ |
212
|
|
|
'http' => [ |
213
|
5 |
|
'method' => strtoupper($this->method), |
214
|
|
|
] |
215
|
|
|
]; |
216
|
|
|
|
217
|
5 |
|
if (!empty($body)) { |
218
|
5 |
|
$headers[] = 'Content-Type: ' . $this->contentType; |
219
|
5 |
|
$options['http']['content'] = $body; |
220
|
|
|
} |
221
|
|
|
|
222
|
5 |
|
if (!empty($this->username)) { |
223
|
1 |
|
$headers[] = 'Authorization: Basic ' . base64_encode($this->username . ':' . $this->password); |
224
|
|
|
} |
225
|
|
|
|
226
|
5 |
|
$options['http']['header'] = implode("\r\n", $headers); |
227
|
5 |
|
$context = stream_context_create($options); |
228
|
|
|
|
229
|
|
|
try { |
230
|
5 |
|
$result = file_get_contents($uri, false, $context); |
|
|
|
|
231
|
4 |
|
} catch (\Throwable $t) { |
232
|
4 |
|
throw new Exception('could not reach webhook: ' . $this->uri); |
233
|
|
|
} |
234
|
1 |
|
} |
235
|
|
|
} |
236
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.